aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2021-09-03 13:07:19 +0000
committerCy Schubert <cy@FreeBSD.org>2021-09-03 13:08:41 +0000
commitc1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5 (patch)
tree03efdf1f5caf99bc853ea6a23dfeb79d15ba348d
parenta0c64a443e4cae67a5eea3a61a47d746866de3ee (diff)
parent2f6c3ea9600b494d24cac5a38c1cea0ac192245e (diff)
downloadsrc-c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5.tar.gz
src-c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5.zip
wpa: Import wpa_supplicant/hostapd commits up to b4f7506ff
Merge vendor commits 40c7ff83e74eabba5a7e2caefeea12372b2d3f9a, efec8223892b3e677acb46eae84ec3534989971f, and 2f6c3ea9600b494d24cac5a38c1cea0ac192245e. Tested by: philip MFC after: 2 months
-rw-r--r--contrib/wpa/CONTRIBUTIONS5
-rw-r--r--contrib/wpa/hostapd/Android.mk1152
-rw-r--r--contrib/wpa/hostapd/ChangeLog4
-rw-r--r--contrib/wpa/hostapd/Makefile1375
-rw-r--r--contrib/wpa/hostapd/android.config214
-rw-r--r--contrib/wpa/hostapd/config_file.c453
-rw-r--r--contrib/wpa/hostapd/ctrl_iface.c908
-rw-r--r--contrib/wpa/hostapd/defconfig35
-rw-r--r--contrib/wpa/hostapd/hostapd.android.rc19
-rw-r--r--contrib/wpa/hostapd/hostapd.conf367
-rw-r--r--contrib/wpa/hostapd/hostapd.wpa_psk6
-rw-r--r--contrib/wpa/hostapd/hostapd_cli.c128
-rw-r--r--contrib/wpa/hostapd/main.c22
-rw-r--r--contrib/wpa/hostapd/sae_pk_gen.c196
-rw-r--r--contrib/wpa/hs20/client/Makefile55
-rw-r--r--contrib/wpa/hs20/client/est.c7
-rw-r--r--contrib/wpa/hs20/client/oma_dm_client.c2
-rw-r--r--contrib/wpa/hs20/client/osu_client.c27
-rw-r--r--contrib/wpa/hs20/client/osu_client.h2
-rw-r--r--contrib/wpa/hs20/client/spp_client.c2
-rw-r--r--contrib/wpa/hs20/server/Makefile42
-rwxr-xr-xcontrib/wpa/hs20/server/ca/clean.sh13
-rw-r--r--contrib/wpa/hs20/server/ca/est-csrattrs.cnf17
-rwxr-xr-xcontrib/wpa/hs20/server/ca/est-csrattrs.sh4
-rw-r--r--contrib/wpa/hs20/server/ca/hs20.oid7
-rwxr-xr-xcontrib/wpa/hs20/server/ca/ocsp-req.sh11
-rwxr-xr-xcontrib/wpa/hs20/server/ca/ocsp-responder-ica.sh3
-rwxr-xr-xcontrib/wpa/hs20/server/ca/ocsp-responder.sh3
-rwxr-xr-xcontrib/wpa/hs20/server/ca/ocsp-update-cache.sh11
-rw-r--r--contrib/wpa/hs20/server/ca/openssl-root.cnf125
-rw-r--r--contrib/wpa/hs20/server/ca/openssl.cnf200
-rwxr-xr-xcontrib/wpa/hs20/server/ca/setup.sh209
-rw-r--r--contrib/wpa/hs20/server/ca/w1fi_logo.pngbin0 -> 7549 bytes
-rw-r--r--contrib/wpa/hs20/server/hs20-osu-server.txt262
-rw-r--r--contrib/wpa/hs20/server/hs20_spp_server.c207
-rw-r--r--contrib/wpa/hs20/server/spp_server.c2933
-rw-r--r--contrib/wpa/hs20/server/spp_server.h36
-rw-r--r--contrib/wpa/hs20/server/sql-example.txt17
-rw-r--r--contrib/wpa/hs20/server/sql.txt108
-rw-r--r--contrib/wpa/hs20/server/www/add-free.php50
-rw-r--r--contrib/wpa/hs20/server/www/add-mo.php56
-rw-r--r--contrib/wpa/hs20/server/www/cert-enroll.php39
-rw-r--r--contrib/wpa/hs20/server/www/config.php7
-rw-r--r--contrib/wpa/hs20/server/www/est.php232
-rw-r--r--contrib/wpa/hs20/server/www/free-remediation.php19
-rw-r--r--contrib/wpa/hs20/server/www/free.php23
-rw-r--r--contrib/wpa/hs20/server/www/redirect.php32
-rw-r--r--contrib/wpa/hs20/server/www/remediation-pw.php41
-rw-r--r--contrib/wpa/hs20/server/www/remediation.php55
-rw-r--r--contrib/wpa/hs20/server/www/signup.php59
-rw-r--r--contrib/wpa/hs20/server/www/spp.php168
-rw-r--r--contrib/wpa/hs20/server/www/terms.php87
-rw-r--r--contrib/wpa/hs20/server/www/users.php377
-rw-r--r--contrib/wpa/src/Makefile12
-rw-r--r--contrib/wpa/src/ap/Makefile60
-rw-r--r--contrib/wpa/src/ap/acs.c357
-rw-r--r--contrib/wpa/src/ap/airtime_policy.c12
-rw-r--r--contrib/wpa/src/ap/ap_config.c298
-rw-r--r--contrib/wpa/src/ap/ap_config.h135
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.c158
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.h51
-rw-r--r--contrib/wpa/src/ap/ap_list.c4
-rw-r--r--contrib/wpa/src/ap/authsrv.c87
-rw-r--r--contrib/wpa/src/ap/beacon.c609
-rw-r--r--contrib/wpa/src/ap/beacon.h2
-rw-r--r--contrib/wpa/src/ap/ctrl_iface_ap.c85
-rw-r--r--contrib/wpa/src/ap/dfs.c330
-rw-r--r--contrib/wpa/src/ap/dfs.h3
-rw-r--r--contrib/wpa/src/ap/dhcp_snoop.c8
-rw-r--r--contrib/wpa/src/ap/dpp_hostapd.c1025
-rw-r--r--contrib/wpa/src/ap/dpp_hostapd.h11
-rw-r--r--contrib/wpa/src/ap/drv_callbacks.c362
-rw-r--r--contrib/wpa/src/ap/fils_hlp.c36
-rw-r--r--contrib/wpa/src/ap/gas_serv.c10
-rw-r--r--contrib/wpa/src/ap/hostapd.c282
-rw-r--r--contrib/wpa/src/ap/hostapd.h59
-rw-r--r--contrib/wpa/src/ap/hs20.c6
-rw-r--r--contrib/wpa/src/ap/hw_features.c373
-rw-r--r--contrib/wpa/src/ap/hw_features.h22
-rw-r--r--contrib/wpa/src/ap/ieee802_11.c2426
-rw-r--r--contrib/wpa/src/ap/ieee802_11.h24
-rw-r--r--contrib/wpa/src/ap/ieee802_11_auth.c172
-rw-r--r--contrib/wpa/src/ap/ieee802_11_auth.h17
-rw-r--r--contrib/wpa/src/ap/ieee802_11_he.c189
-rw-r--r--contrib/wpa/src/ap/ieee802_11_ht.c30
-rw-r--r--contrib/wpa/src/ap/ieee802_11_shared.c189
-rw-r--r--contrib/wpa/src/ap/ieee802_11_vht.c176
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.c482
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.h7
-rw-r--r--contrib/wpa/src/ap/neighbor_db.c58
-rw-r--r--contrib/wpa/src/ap/neighbor_db.h1
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.c6
-rw-r--r--contrib/wpa/src/ap/preauth_auth.c2
-rw-r--r--contrib/wpa/src/ap/sta_info.c111
-rw-r--r--contrib/wpa/src/ap/sta_info.h54
-rw-r--r--contrib/wpa/src/ap/utils.c4
-rw-r--r--contrib/wpa/src/ap/vlan_init.c5
-rw-r--r--contrib/wpa/src/ap/wmm.c14
-rw-r--r--contrib/wpa/src/ap/wnm_ap.c83
-rw-r--r--contrib/wpa/src/ap/wpa_auth.c1415
-rw-r--r--contrib/wpa/src/ap/wpa_auth.h103
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ft.c385
-rw-r--r--contrib/wpa/src/ap/wpa_auth_glue.c343
-rw-r--r--contrib/wpa/src/ap/wpa_auth_i.h71
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.c444
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.h35
-rw-r--r--contrib/wpa/src/ap/wpa_auth_kay.c12
-rw-r--r--contrib/wpa/src/ap/wps_hostapd.c237
-rw-r--r--contrib/wpa/src/build.rules109
-rw-r--r--contrib/wpa/src/common/Makefile16
-rw-r--r--contrib/wpa/src/common/brcm_vendor.h156
-rw-r--r--contrib/wpa/src/common/common_module_tests.c513
-rw-r--r--contrib/wpa/src/common/defs.h86
-rw-r--r--contrib/wpa/src/common/dhcp.h2
-rw-r--r--contrib/wpa/src/common/dpp.c8787
-rw-r--r--contrib/wpa/src/common/dpp.h248
-rw-r--r--contrib/wpa/src/common/dpp_auth.c1977
-rw-r--r--contrib/wpa/src/common/dpp_backup.c1265
-rw-r--r--contrib/wpa/src/common/dpp_crypto.c3329
-rw-r--r--contrib/wpa/src/common/dpp_i.h160
-rw-r--r--contrib/wpa/src/common/dpp_pkex.c1324
-rw-r--r--contrib/wpa/src/common/dpp_reconfig.c958
-rw-r--r--contrib/wpa/src/common/dpp_tcp.c1824
-rw-r--r--contrib/wpa/src/common/gas_server.c140
-rw-r--r--contrib/wpa/src/common/gas_server.h9
-rw-r--r--contrib/wpa/src/common/hw_features_common.c427
-rw-r--r--contrib/wpa/src/common/hw_features_common.h26
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.c789
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.h70
-rw-r--r--contrib/wpa/src/common/ieee802_11_defs.h249
-rw-r--r--contrib/wpa/src/common/linux_bridge.h39
-rw-r--r--contrib/wpa/src/common/linux_vlan.h52
-rw-r--r--contrib/wpa/src/common/ocv.c39
-rw-r--r--contrib/wpa/src/common/ocv.h13
-rw-r--r--contrib/wpa/src/common/privsep_commands.h1
-rw-r--r--contrib/wpa/src/common/ptksa_cache.c321
-rw-r--r--contrib/wpa/src/common/ptksa_cache.h79
-rw-r--r--contrib/wpa/src/common/qca-vendor.h4187
-rw-r--r--contrib/wpa/src/common/sae.c1387
-rw-r--r--contrib/wpa/src/common/sae.h109
-rw-r--r--contrib/wpa/src/common/sae_pk.c884
-rw-r--r--contrib/wpa/src/common/version.h2
-rw-r--r--contrib/wpa/src/common/wpa_common.c1240
-rw-r--r--contrib/wpa/src/common/wpa_common.h207
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.c5
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.h41
-rw-r--r--contrib/wpa/src/crypto/Makefile60
-rw-r--r--contrib/wpa/src/crypto/crypto.h49
-rw-r--r--contrib/wpa/src/crypto/crypto_module_tests.c150
-rw-r--r--contrib/wpa/src/crypto/crypto_openssl.c250
-rw-r--r--contrib/wpa/src/crypto/crypto_wolfssl.c77
-rw-r--r--contrib/wpa/src/crypto/sha256.c6
-rw-r--r--contrib/wpa/src/crypto/sha384-tlsprf.c71
-rw-r--r--contrib/wpa/src/crypto/sha384.c6
-rw-r--r--contrib/wpa/src/crypto/sha384.h3
-rw-r--r--contrib/wpa/src/crypto/sha512.c6
-rw-r--r--contrib/wpa/src/crypto/tls.h14
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.c304
-rw-r--r--contrib/wpa/src/crypto/tls_wolfssl.c65
-rw-r--r--contrib/wpa/src/drivers/Makefile9
-rw-r--r--contrib/wpa/src/drivers/android_drv.h56
-rw-r--r--contrib/wpa/src/drivers/driver.h716
-rw-r--r--contrib/wpa/src/drivers/driver_atheros.c41
-rw-r--r--contrib/wpa/src/drivers/driver_bsd.c659
-rw-r--r--contrib/wpa/src/drivers/driver_common.c21
-rw-r--r--contrib/wpa/src/drivers/driver_hostap.c24
-rw-r--r--contrib/wpa/src/drivers/driver_hostap.h210
-rw-r--r--contrib/wpa/src/drivers/driver_macsec_linux.c87
-rw-r--r--contrib/wpa/src/drivers/driver_macsec_qca.c34
-rw-r--r--contrib/wpa/src/drivers/driver_ndis.c47
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211.c12229
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211.h65
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_android.c4
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_capa.c579
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_event.c580
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_monitor.c3
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_scan.c51
-rw-r--r--contrib/wpa/src/drivers/driver_none.c77
-rw-r--r--contrib/wpa/src/drivers/driver_openbsd.c10
-rw-r--r--contrib/wpa/src/drivers/driver_privsep.c18
-rw-r--r--contrib/wpa/src/drivers/driver_roboswitch.c487
-rw-r--r--contrib/wpa/src/drivers/driver_wext.c2499
-rw-r--r--contrib/wpa/src/drivers/driver_wext.h77
-rw-r--r--contrib/wpa/src/drivers/drivers.mak220
-rw-r--r--contrib/wpa/src/drivers/drivers.mk196
-rw-r--r--contrib/wpa/src/drivers/linux_ioctl.c237
-rw-r--r--contrib/wpa/src/drivers/linux_ioctl.h23
-rw-r--r--contrib/wpa/src/drivers/linux_wext.h45
-rw-r--r--contrib/wpa/src/drivers/netlink.c226
-rw-r--r--contrib/wpa/src/drivers/netlink.h28
-rw-r--r--contrib/wpa/src/drivers/nl80211_copy.h973
-rw-r--r--contrib/wpa/src/drivers/priv_netlink.h109
-rw-r--r--contrib/wpa/src/drivers/rfkill.c224
-rw-r--r--contrib/wpa/src/drivers/rfkill.h25
-rw-r--r--contrib/wpa/src/eap_common/Makefile18
-rw-r--r--contrib/wpa/src/eap_common/eap_common.c8
-rw-r--r--contrib/wpa/src/eap_common/eap_common.h8
-rw-r--r--contrib/wpa/src/eap_common/eap_defs.h4
-rw-r--r--contrib/wpa/src/eap_common/eap_sim_common.c28
-rw-r--r--contrib/wpa/src/eap_common/eap_teap_common.c72
-rw-r--r--contrib/wpa/src/eap_common/eap_teap_common.h22
-rw-r--r--contrib/wpa/src/eap_peer/Makefile7
-rw-r--r--contrib/wpa/src/eap_peer/eap.c220
-rw-r--r--contrib/wpa/src/eap_peer/eap.h13
-rw-r--r--contrib/wpa/src/eap_peer/eap_aka.c48
-rw-r--r--contrib/wpa/src/eap_peer/eap_config.h408
-rw-r--r--contrib/wpa/src/eap_peer/eap_eke.c16
-rw-r--r--contrib/wpa/src/eap_peer/eap_fast.c54
-rw-r--r--contrib/wpa/src/eap_peer/eap_gpsk.c14
-rw-r--r--contrib/wpa/src/eap_peer/eap_gtc.c8
-rw-r--r--contrib/wpa/src/eap_peer/eap_i.h42
-rw-r--r--contrib/wpa/src/eap_peer/eap_ikev2.c28
-rw-r--r--contrib/wpa/src/eap_peer/eap_leap.c44
-rw-r--r--contrib/wpa/src/eap_peer/eap_md5.c12
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.c12
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.h14
-rw-r--r--contrib/wpa/src/eap_peer/eap_mschapv2.c32
-rw-r--r--contrib/wpa/src/eap_peer/eap_otp.c8
-rw-r--r--contrib/wpa/src/eap_peer/eap_pax.c50
-rw-r--r--contrib/wpa/src/eap_peer/eap_peap.c71
-rw-r--r--contrib/wpa/src/eap_peer/eap_psk.c22
-rw-r--r--contrib/wpa/src/eap_peer/eap_pwd.c22
-rw-r--r--contrib/wpa/src/eap_peer/eap_sake.c26
-rw-r--r--contrib/wpa/src/eap_peer/eap_sim.c44
-rw-r--r--contrib/wpa/src/eap_peer/eap_teap.c201
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls.c42
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.c103
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.h10
-rw-r--r--contrib/wpa/src/eap_peer/eap_tnc.c32
-rw-r--r--contrib/wpa/src/eap_peer/eap_ttls.c88
-rw-r--r--contrib/wpa/src/eap_peer/eap_vendor_test.c16
-rw-r--r--contrib/wpa/src/eap_peer/eap_wsc.c24
-rw-r--r--contrib/wpa/src/eap_peer/ikev2.c10
-rw-r--r--contrib/wpa/src/eap_peer/tncc.c5
-rw-r--r--contrib/wpa/src/eap_server/Makefile8
-rw-r--r--contrib/wpa/src/eap_server/eap.h172
-rw-r--r--contrib/wpa/src/eap_server/eap_i.h67
-rw-r--r--contrib/wpa/src/eap_server/eap_methods.h9
-rw-r--r--contrib/wpa/src/eap_server/eap_server.c291
-rw-r--r--contrib/wpa/src/eap_server/eap_server_aka.c74
-rw-r--r--contrib/wpa/src/eap_server/eap_server_eke.c39
-rw-r--r--contrib/wpa/src/eap_server/eap_server_fast.c106
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gpsk.c37
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gtc.c12
-rw-r--r--contrib/wpa/src/eap_server/eap_server_identity.c14
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ikev2.c22
-rw-r--r--contrib/wpa/src/eap_server/eap_server_md5.c14
-rw-r--r--contrib/wpa/src/eap_server/eap_server_methods.c10
-rw-r--r--contrib/wpa/src/eap_server/eap_server_mschapv2.c22
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pax.c32
-rw-r--r--contrib/wpa/src/eap_server/eap_server_peap.c103
-rw-r--r--contrib/wpa/src/eap_server/eap_server_psk.c34
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pwd.c22
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sake.c38
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sim.c66
-rw-r--r--contrib/wpa/src/eap_server/eap_server_teap.c309
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls.c54
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls_common.c93
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tnc.c26
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ttls.c96
-rw-r--r--contrib/wpa/src/eap_server/eap_server_vendor_test.c12
-rw-r--r--contrib/wpa/src/eap_server/eap_server_wsc.c32
-rw-r--r--contrib/wpa/src/eap_server/eap_tls_common.h2
-rw-r--r--contrib/wpa/src/eap_server/tncs.c5
-rw-r--r--contrib/wpa/src/eapol_auth/Makefile2
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.c206
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.h26
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h40
-rw-r--r--contrib/wpa/src/eapol_supp/Makefile5
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.c218
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.h29
-rw-r--r--contrib/wpa/src/fst/fst.c25
-rw-r--r--contrib/wpa/src/fst/fst.h23
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_aux.h4
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_iface.c48
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_iface.h2
-rw-r--r--contrib/wpa/src/fst/fst_group.c10
-rw-r--r--contrib/wpa/src/fst/fst_group.h4
-rw-r--r--contrib/wpa/src/fst/fst_iface.c8
-rw-r--r--contrib/wpa/src/fst/fst_iface.h8
-rw-r--r--contrib/wpa/src/fst/fst_session.c96
-rw-r--r--contrib/wpa/src/fst/fst_session.h12
-rw-r--r--contrib/wpa/src/l2_packet/Makefile3
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet.h4
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_freebsd.c5
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_linux.c515
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_ndis.c3
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_none.c4
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_pcap.c400
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_privsep.c3
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_winpcap.c350
-rw-r--r--contrib/wpa/src/lib.rules29
-rw-r--r--contrib/wpa/src/objs.mk3
-rw-r--r--contrib/wpa/src/p2p/Makefile16
-rw-r--r--contrib/wpa/src/p2p/p2p.c147
-rw-r--r--contrib/wpa/src/p2p/p2p.h31
-rw-r--r--contrib/wpa/src/p2p/p2p_go_neg.c9
-rw-r--r--contrib/wpa/src/p2p/p2p_i.h5
-rw-r--r--contrib/wpa/src/p2p/p2p_invitation.c5
-rw-r--r--contrib/wpa/src/p2p/p2p_utils.c39
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.c177
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.h10
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.c608
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.h68
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay_i.h40
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.c22
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.h8
-rw-r--r--contrib/wpa/src/radius/Makefile9
-rw-r--r--contrib/wpa/src/radius/radius.c2
-rw-r--r--contrib/wpa/src/radius/radius.h3
-rw-r--r--contrib/wpa/src/radius/radius_client.c55
-rw-r--r--contrib/wpa/src/radius/radius_client.h5
-rw-r--r--contrib/wpa/src/radius/radius_server.c283
-rw-r--r--contrib/wpa/src/radius/radius_server.h142
-rw-r--r--contrib/wpa/src/rsn_supp/Makefile14
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.c54
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.h7
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.c24
-rw-r--r--contrib/wpa/src/rsn_supp/tdls.c71
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.c759
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.h93
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ft.c399
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_i.h88
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.c317
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.h52
-rw-r--r--contrib/wpa/src/tls/Makefile25
-rw-r--r--contrib/wpa/src/tls/asn1.c396
-rw-r--r--contrib/wpa/src/tls/asn1.h146
-rw-r--r--contrib/wpa/src/tls/pkcs1.c55
-rw-r--r--contrib/wpa/src/tls/pkcs5.c78
-rw-r--r--contrib/wpa/src/tls/pkcs8.c59
-rw-r--r--contrib/wpa/src/tls/rsa.c23
-rw-r--r--contrib/wpa/src/tls/tlsv1_client.c29
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_i.h4
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_ocsp.c180
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_read.c10
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_write.c18
-rw-r--r--contrib/wpa/src/tls/tlsv1_cred.c247
-rw-r--r--contrib/wpa/src/tls/x509v3.c419
-rw-r--r--contrib/wpa/src/tls/x509v3.h7
-rw-r--r--contrib/wpa/src/utils/Makefile30
-rw-r--r--contrib/wpa/src/utils/base64.c59
-rw-r--r--contrib/wpa/src/utils/base64.h13
-rw-r--r--contrib/wpa/src/utils/browser-android.c2
-rw-r--r--contrib/wpa/src/utils/browser-system.c2
-rw-r--r--contrib/wpa/src/utils/browser-wpadebug.c2
-rw-r--r--contrib/wpa/src/utils/browser.c210
-rw-r--r--contrib/wpa/src/utils/browser.h4
-rw-r--r--contrib/wpa/src/utils/build_config.h4
-rw-r--r--contrib/wpa/src/utils/common.c38
-rw-r--r--contrib/wpa/src/utils/common.h8
-rw-r--r--contrib/wpa/src/utils/config.c97
-rw-r--r--contrib/wpa/src/utils/config.h29
-rw-r--r--contrib/wpa/src/utils/eloop.c47
-rw-r--r--contrib/wpa/src/utils/eloop_win.c8
-rw-r--r--contrib/wpa/src/utils/ext_password.c3
-rw-r--r--contrib/wpa/src/utils/ext_password_file.c136
-rw-r--r--contrib/wpa/src/utils/ext_password_i.h4
-rw-r--r--contrib/wpa/src/utils/http-utils.h6
-rw-r--r--contrib/wpa/src/utils/includes.h1
-rw-r--r--contrib/wpa/src/utils/json.c122
-rw-r--r--contrib/wpa/src/utils/json.h15
-rw-r--r--contrib/wpa/src/utils/list.h8
-rw-r--r--contrib/wpa/src/utils/os_internal.c6
-rw-r--r--contrib/wpa/src/utils/os_unix.c46
-rw-r--r--contrib/wpa/src/utils/platform.h23
-rw-r--r--contrib/wpa/src/utils/radiotap.c12
-rw-r--r--contrib/wpa/src/utils/radiotap.h407
-rw-r--r--contrib/wpa/src/utils/state_machine.h8
-rw-r--r--contrib/wpa/src/utils/trace.c11
-rw-r--r--contrib/wpa/src/utils/utils_module_tests.c39
-rw-r--r--contrib/wpa/src/utils/wpa_debug.c147
-rw-r--r--contrib/wpa/src/utils/wpa_debug.h3
-rw-r--r--contrib/wpa/src/utils/wpabuf.h27
-rw-r--r--contrib/wpa/src/utils/xml_libxml2.c2
-rw-r--r--contrib/wpa/src/wps/Makefile28
-rw-r--r--contrib/wpa/src/wps/upnp_xml.c2
-rw-r--r--contrib/wpa/src/wps/wps.h23
-rw-r--r--contrib/wpa/src/wps/wps_attr_build.c15
-rw-r--r--contrib/wpa/src/wps/wps_attr_process.c9
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.c17
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.h1
-rw-r--r--contrib/wpa/src/wps/wps_enrollee.c11
-rw-r--r--contrib/wpa/src/wps/wps_er.c4
-rw-r--r--contrib/wpa/src/wps/wps_registrar.c139
-rw-r--r--contrib/wpa/src/wps/wps_upnp.c28
-rw-r--r--contrib/wpa/src/wps/wps_upnp_ap.c4
-rw-r--r--contrib/wpa/src/wps/wps_upnp_event.c27
-rw-r--r--contrib/wpa/src/wps/wps_upnp_i.h9
-rw-r--r--contrib/wpa/src/wps/wps_upnp_web.c4
-rw-r--r--contrib/wpa/wpa_supplicant/Android.mk114
-rw-r--r--contrib/wpa/wpa_supplicant/ChangeLog10
-rw-r--r--contrib/wpa/wpa_supplicant/Makefile2073
-rw-r--r--contrib/wpa/wpa_supplicant/README4
-rw-r--r--contrib/wpa/wpa_supplicant/README-DPP71
-rw-r--r--contrib/wpa/wpa_supplicant/README-HS202
-rw-r--r--contrib/wpa/wpa_supplicant/android.config16
-rw-r--r--contrib/wpa/wpa_supplicant/ap.c257
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder.h2
-rw-r--r--contrib/wpa/wpa_supplicant/bss.c145
-rw-r--r--contrib/wpa/wpa_supplicant/bss.h25
-rw-r--r--contrib/wpa/wpa_supplicant/bssid_ignore.c221
-rw-r--r--contrib/wpa/wpa_supplicant/bssid_ignore.h33
-rw-r--r--contrib/wpa/wpa_supplicant/config.c644
-rw-r--r--contrib/wpa/wpa_supplicant/config.h129
-rw-r--r--contrib/wpa/wpa_supplicant/config_file.c243
-rw-r--r--contrib/wpa/wpa_supplicant/config_ssid.h155
-rw-r--r--contrib/wpa/wpa_supplicant/config_winreg.c1061
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface.c1375
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface.h16
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c7
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_udp.c63
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_unix.c73
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_common.c23
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new.c76
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c424
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h6
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c84
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c2
-rw-r--r--contrib/wpa/wpa_supplicant/defconfig45
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/Makefile28
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/eapol_test.sgml209
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_background.sgml105
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_cli.sgml360
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_gui.sgml106
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_passphrase.sgml77
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_priv.sgml152
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml243
-rw-r--r--contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.sgml764
-rw-r--r--contrib/wpa/wpa_supplicant/dpp_supplicant.c1800
-rw-r--r--contrib/wpa/wpa_supplicant/dpp_supplicant.h15
-rw-r--r--contrib/wpa/wpa_supplicant/driver_i.h109
-rw-r--r--contrib/wpa/wpa_supplicant/eapol_test.c15
-rw-r--r--contrib/wpa/wpa_supplicant/events.c1523
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/dpp-nfc.py1186
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/p2p-action-udhcp.sh4
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/p2p-action.sh4
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py18
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py2
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py2
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py2
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py14
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py10
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py2
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py2
-rw-r--r--contrib/wpa/wpa_supplicant/examples/udhcpd-p2p.conf12
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.c62
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.h2
-rw-r--r--contrib/wpa/wpa_supplicant/hs20_supplicant.c30
-rw-r--r--contrib/wpa/wpa_supplicant/ibss_rsn.c45
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.c66
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.h2
-rw-r--r--contrib/wpa/wpa_supplicant/main.c10
-rw-r--r--contrib/wpa/wpa_supplicant/main_winmain.c78
-rw-r--r--contrib/wpa/wpa_supplicant/main_winsvc.c458
-rw-r--r--contrib/wpa/wpa_supplicant/mbo.c30
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.c243
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.h6
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_mpm.c49
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_rsn.c27
-rw-r--r--contrib/wpa/wpa_supplicant/nmake.mak2
-rw-r--r--contrib/wpa/wpa_supplicant/notify.c10
-rw-r--r--contrib/wpa/wpa_supplicant/offchannel.c6
-rw-r--r--contrib/wpa/wpa_supplicant/op_classes.c239
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.c667
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.h32
-rw-r--r--contrib/wpa/wpa_supplicant/pasn_supplicant.c1714
-rw-r--r--contrib/wpa/wpa_supplicant/preauth_test.c20
-rw-r--r--contrib/wpa/wpa_supplicant/robust_av.c155
-rw-r--r--contrib/wpa/wpa_supplicant/rrm.c91
-rw-r--r--contrib/wpa/wpa_supplicant/scan.c703
-rw-r--r--contrib/wpa/wpa_supplicant/scan.h33
-rw-r--r--contrib/wpa/wpa_supplicant/sme.c531
-rw-r--r--contrib/wpa/wpa_supplicant/sme.h8
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in2
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in2
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in2
-rw-r--r--contrib/wpa/wpa_supplicant/twt.c142
-rwxr-xr-xcontrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj6
-rwxr-xr-xcontrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj6
-rwxr-xr-xcontrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj6
-rw-r--r--contrib/wpa/wpa_supplicant/wmm_ac.c2
-rw-r--r--contrib/wpa/wpa_supplicant/wnm_sta.c33
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_cli.c339
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_passphrase.c8
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_priv.c32
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.c1283
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.conf196
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant_i.h249
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_glue.c222
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_glue.h2
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_kay.c12
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_module_tests.c85
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.c85
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.h5
-rw-r--r--usr.sbin/wpa/Makefile.crypto1
-rw-r--r--usr.sbin/wpa/Makefile.inc5
-rw-r--r--usr.sbin/wpa/hostapd/Makefile2
-rw-r--r--usr.sbin/wpa/src/ap/Makefile9
-rw-r--r--usr.sbin/wpa/src/common/Makefile3
-rw-r--r--usr.sbin/wpa/src/crypto/Makefile5
-rw-r--r--usr.sbin/wpa/src/rsn_supp/Makefile4
-rw-r--r--usr.sbin/wpa/src/utils/Makefile2
-rw-r--r--usr.sbin/wpa/wpa_supplicant/Makefile7
504 files changed, 91123 insertions, 19030 deletions
diff --git a/contrib/wpa/CONTRIBUTIONS b/contrib/wpa/CONTRIBUTIONS
index c81ad640995a..1b4caf7ac811 100644
--- a/contrib/wpa/CONTRIBUTIONS
+++ b/contrib/wpa/CONTRIBUTIONS
@@ -56,6 +56,9 @@ In general, the best way of generating a suitable formatted patch file
is by committing the changes to a cloned git repository and using git
format-patch. The patch can then be sent, e.g., with git send-email.
+A list of pending patches waiting for review is available in
+Patchwork: https://patchwork.ozlabs.org/project/hostap/list/
+
History of license and contributions terms
------------------------------------------
@@ -140,7 +143,7 @@ The license terms used for hostap.git files
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/contrib/wpa/hostapd/Android.mk b/contrib/wpa/hostapd/Android.mk
new file mode 100644
index 000000000000..dd8aa2450d7e
--- /dev/null
+++ b/contrib/wpa/hostapd/Android.mk
@@ -0,0 +1,1152 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+WPA_BUILD_HOSTAPD := false
+ifneq ($(BOARD_HOSTAPD_DRIVER),)
+ WPA_BUILD_HOSTAPD := true
+ CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
+endif
+
+ifeq ($(WPA_BUILD_HOSTAPD),true)
+
+include $(LOCAL_PATH)/android.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
+
+# Disable unused parameter warnings
+L_CFLAGS += -Wno-unused-parameter
+
+# Set Android extended P2P functionality
+L_CFLAGS += -DANDROID_P2P
+
+ifeq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+L_CFLAGS += -DANDROID_LIB_STUB
+endif
+
+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB_EVENT),)
+L_CFLAGS += -DANDROID_LIB_EVENT
+endif
+
+# Use Android specific directory for control interface sockets
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\"
+
+# Use Android specific directory for hostapd_cli command completion history
+L_CFLAGS += -DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/misc/wifi\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += system/security/keystore/include
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+INCLUDES += external/libnl/include
+else
+INCLUDES += external/libnl-headers
+endif
+endif
+
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = main.c
+OBJS += config_file.c
+
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/preauth_auth.c
+OBJS += src/ap/pmksa_cache_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
+OBJS_d =
+OBJS_p =
+LIBS =
+LIBS_c =
+HOBJS =
+LIBS_h =
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += src/drivers/drivers.c
+L_CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+HOBJS += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+OBJS += src/utils/eloop.c
+
+ifdef CONFIG_ELOOP_POLL
+L_CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+ifdef CONFIG_ELOOP_EPOLL
+L_CFLAGS += -DCONFIG_ELOOP_EPOLL
+endif
+
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
+
+OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/wpa_common.c
+OBJS += src/common/hw_features_common.c
+
+OBJS += src/eapol_auth/eapol_auth_sm.c
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
+L_CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += src/eapol_auth/eapol_auth_dump.c
+endif
+
+ifdef CONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += src/radius/radius.c
+OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += src/ap/accounting.c
+endif
+
+ifdef CONFIG_NO_VLAN
+L_CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += src/ap/vlan_init.c
+OBJS += src/ap/vlan_ifconfig.c
+OBJS += src/ap/vlan.c
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_full.c
+ifdef CONFIG_VLAN_NETLINK
+OBJS += src/ap/vlan_util.c
+else
+OBJS += src/ap/vlan_ioctl.c
+endif
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += src/common/ctrl_iface_common.c
+OBJS += ctrl_iface.c
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_RSN_PREAUTH
+L_CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_HS20
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+endif
+
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
+OBJS += src/ap/wpa_auth_ft.c
+NEED_AES_UNWRAP=y
+NEED_AES_SIV=y
+NEED_ETH_P_OUI=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
+ifdef NEED_ETH_P_OUI
+L_CFLAGS += -DCONFIG_ETH_P_OUI
+OBJS += src/ap/eth_p_oui.c
+endif
+
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
+NEED_ECC=y
+NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_DRAGONFLY=y
+endif
+
+ifdef CONFIG_OWE
+L_CFLAGS += -DCONFIG_OWE
+NEED_ECC=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+endif
+
+ifdef CONFIG_FILS
+L_CFLAGS += -DCONFIG_FILS
+OBJS += src/ap/fils_hlp.c
+NEED_SHA384=y
+NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+L_CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
+OBJS += src/ap/wnm_ap.c
+endif
+
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
+ifdef CONFIG_IEEE80211AX
+L_CFLAGS += -DCONFIG_IEEE80211AX
+endif
+
+ifdef CONFIG_MBO
+L_CFLAGS += -DCONFIG_MBO
+OBJS += src/ap/mbo_ap.c
+endif
+
+ifdef CONFIG_FST
+L_CFLAGS += -DCONFIG_FST
+OBJS += src/fst/fst.c
+OBJS += src/fst/fst_group.c
+OBJS += src/fst/fst_iface.c
+OBJS += src/fst/fst_session.c
+OBJS += src/fst/fst_ctrl_aux.c
+ifdef CONFIG_FST_TEST
+L_CFLAGS += -DCONFIG_FST_TEST
+endif
+ifndef CONFIG_NO_CTRL_IFACE
+OBJS += src/fst/fst_ctrl_iface.c
+endif
+endif
+
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+L_CFLAGS += -DCONFIG_NO_TKIP
+endif
+
+
+include $(LOCAL_PATH)/src/drivers/drivers.mk
+
+OBJS += $(DRV_AP_OBJS)
+L_CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += src/l2_packet/l2_packet_freebsd.c
+else
+LIBS += -ldnet -lpcap
+OBJS += src/l2_packet/l2_packet_pcap.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_linux.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_none.c
+endif
+
+
+ifdef CONFIG_EAP_MD5
+L_CFLAGS += -DEAP_SERVER_MD5
+OBJS += src/eap_server/eap_server_md5.c
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+L_CFLAGS += -DEAP_SERVER_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
+ifdef CONFIG_EAP_PEAP
+L_CFLAGS += -DEAP_SERVER_PEAP
+OBJS += src/eap_server/eap_server_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+L_CFLAGS += -DEAP_SERVER_TTLS
+OBJS += src/eap_server/eap_server_ttls.c
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+L_CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += src/eap_server/eap_server_mschapv2.c
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+L_CFLAGS += -DEAP_SERVER_GTC
+OBJS += src/eap_server/eap_server_gtc.c
+endif
+
+ifdef CONFIG_EAP_SIM
+L_CFLAGS += -DEAP_SERVER_SIM
+OBJS += src/eap_server/eap_server_sim.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+L_CFLAGS += -DEAP_SERVER_AKA
+OBJS += src/eap_server/eap_server_aka.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+L_CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementing the interface specified in
+# eap_sim_db.h.
+OBJS += src/eap_server/eap_sim_db.c
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+L_CFLAGS += -DEAP_SERVER_PAX
+OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c
+endif
+
+ifdef CONFIG_EAP_PSK
+L_CFLAGS += -DEAP_SERVER_PSK
+OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+L_CFLAGS += -DEAP_SERVER_SAKE
+OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c
+endif
+
+ifdef CONFIG_EAP_GPSK
+L_CFLAGS += -DEAP_SERVER_GPSK
+OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
+endif
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_SERVER_PWD
+OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
+NEED_ECC=y
+NEED_DRAGONFLY=y
+endif
+
+ifdef CONFIG_EAP_EKE
+L_CFLAGS += -DEAP_SERVER_EKE
+OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += src/eap_server/eap_server_vendor_test.c
+endif
+
+ifdef CONFIG_EAP_FAST
+L_CFLAGS += -DEAP_SERVER_FAST
+OBJS += src/eap_server/eap_server_fast.c
+OBJS += src/eap_common/eap_fast_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_EAP_TEAP
+L_CFLAGS += -DEAP_SERVER_TEAP
+OBJS += src/eap_server/eap_server_teap.c
+OBJS += src/eap_common/eap_teap_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += src/utils/uuid.c
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+NEED_DH_GROUPS=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+L_CFLAGS += -DCONFIG_WPS_NFC
+OBJS += src/wps/ndef.c
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_DPP
+L_CFLAGS += -DCONFIG_DPP
+OBJS += src/common/dpp.c
+OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
+OBJS += src/common/dpp_crypto.c
+OBJS += src/common/dpp_pkex.c
+OBJS += src/common/dpp_reconfig.c
+OBJS += src/common/dpp_tcp.c
+OBJS += src/ap/dpp_hostapd.c
+OBJS += src/ap/gas_query_ap.c
+NEED_AES_SIV=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+NEED_ECC=y
+NEED_JSON=y
+NEED_GAS=y
+NEED_BASE64=y
+NEED_ASN1=y
+ifdef CONFIG_DPP2
+L_CFLAGS += -DCONFIG_DPP2
+endif
+endif
+
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+endif
+
+ifdef CONFIG_EAP_IKEV2
+L_CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+L_CFLAGS += -DEAP_SERVER_TNC
+OBJS += src/eap_server/eap_server_tnc.c
+OBJS += src/eap_server/tncs.c
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.c
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_common/eap_common.c
+OBJS += src/eap_server/eap_server_methods.c
+OBJS += src/eap_server/eap_server_identity.c
+L_CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+L_CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef NEED_DRAGONFLY
+OBJS += src/common/dragonfly.c
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+L_CFLAGS += -DEAP_TLS_FUNCS
+OBJS += src/eap_server/eap_server_tls_common.c
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_openssl.c
+OBJS += src/crypto/tls_openssl_ocsp.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+HOBJS += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+ifndef CONFIG_TLS_DEFAULT_CIPHERS
+CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
+endif
+L_CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+HOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_internal.c
+OBJS += src/crypto/sha1-internal.c
+endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_server.c
+OBJS += src/tls/tlsv1_server_write.c
+OBJS += src/tls/tlsv1_server_read.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_ASN1=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+NEED_AES_DEC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+AESOBJS += src/crypto/aes-wrap.c
+endif
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+AESOBJS += src/crypto/aes-omac1.c
+ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-unwrap.c
+endif
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
+AESOBJS += src/crypto/aes-cbc.c
+endif
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-dec.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+SHA1OBJS += src/crypto/sha1.c
+endif
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += src/crypto/sha1-internal.c
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += src/crypto/fips_prf_internal.c
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/md5.c
+endif
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += src/crypto/md5-internal.c
+HOBJS += src/crypto/md5-internal.c
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef CONFIG_NO_RC4
+L_CFLAGS += -DCONFIG_NO_RC4
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+ifndef CONFIG_NO_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+endif
+
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/sha256.c
+endif
+endif
+OBJS += src/crypto/sha256-prf.c
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += src/crypto/sha256-internal.c
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += src/crypto/sha384-tlsprf.c
+endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += src/crypto/sha256-kdf.c
+endif
+ifdef NEED_HMAC_SHA384_KDF
+OBJS += src/crypto/sha384-kdf.c
+endif
+ifdef NEED_HMAC_SHA512_KDF
+OBJS += src/crypto/sha512-kdf.c
+endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/sha384.c
+endif
+endif
+OBJS += src/crypto/sha384-prf.c
+endif
+ifdef NEED_SHA512
+L_CFLAGS += -DCONFIG_SHA512
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/sha512.c
+endif
+endif
+endif
+OBJS += src/crypto/sha512-prf.c
+endif
+
+ifdef CONFIG_INTERNAL_SHA384
+L_CFLAGS += -DCONFIG_INTERNAL_SHA384
+OBJS += src/crypto/sha384-internal.c
+endif
+
+ifdef CONFIG_INTERNAL_SHA512
+L_CFLAGS += -DCONFIG_INTERNAL_SHA512
+OBJS += src/crypto/sha512-internal.c
+endif
+
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
+HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
+HOBJS += src/crypto/md5.c
+endif
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+L_CFLAGS += -DRADIUS_SERVER
+OBJS += src/radius/radius_server.c
+endif
+
+ifdef CONFIG_IPV6
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_JSON
+OBJS += src/utils/json.c
+L_CFLAGS += -DCONFIG_JSON
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+OBJS += src/ap/ieee802_11_ht.c
+
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
+ifdef CONFIG_IEEE80211AX
+OBJS += src/ap/ieee802_11_he.c
+endif
+
+ifdef CONFIG_P2P_MANAGER
+L_CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += src/ap/p2p_hostapd.c
+endif
+
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
+ifdef NEED_GAS
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
+ifdef CONFIG_PROXYARP
+L_CFLAGS += -DCONFIG_PROXYARP
+OBJS += src/ap/x_snoop.c
+OBJS += src/ap/dhcp_snoop.c
+ifdef CONFIG_IPV6
+OBJS += src/ap/ndisc_snoop.c
+endif
+endif
+
+OBJS += src/drivers/driver_common.c
+
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+L_CFLAGS += -DCONFIG_DEBUG_SYSLOG
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+OBJS_c = hostapd_cli.c
+OBJS_c += src/common/wpa_ctrl.c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/common/cli.c
+OBJS_c += src/utils/eloop.c
+OBJS_c += src/utils/common.c
+ifdef CONFIG_WPA_TRACE
+OBJS_c += src/utils/trace.c
+endif
+OBJS_c += src/utils/wpa_debug.c
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd
+LOCAL_MODULE_TAGS := optional
+LOCAL_PROPRIETARY_MODULE := true
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+LOCAL_SHARED_LIBRARIES += libnl
+else
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_INIT_RC := hostapd.android.rc
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog
index 6c4410e8ec62..34a8a081879d 100644
--- a/contrib/wpa/hostapd/ChangeLog
+++ b/contrib/wpa/hostapd/ChangeLog
@@ -362,7 +362,7 @@ ChangeLog for hostapd
* RADIUS server functionality
- add minimal RADIUS accounting server support (hostapd-as-server);
this is mainly to enable testing coverage with hwsim scripts
- - allow authentication log to be written into SQLite databse
+ - allow authentication log to be written into SQLite database
- added option for TLS protocol testing of an EAP peer by simulating
various misbehaviors/known attacks
- MAC ACL support for testing purposes
@@ -668,7 +668,7 @@ ChangeLog for hostapd
* fixed HT Capabilities IE with nl80211 drivers
* moved generic AP functionality code into src/ap
* WPS: handle Selected Registrar as union of info from all Registrars
- * remove obsolte Prism54.org driver wrapper
+ * remove obsolete Prism54.org driver wrapper
* added internal debugging mechanism with backtrace support and memory
allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
diff --git a/contrib/wpa/hostapd/Makefile b/contrib/wpa/hostapd/Makefile
new file mode 100644
index 000000000000..ac085fd10520
--- /dev/null
+++ b/contrib/wpa/hostapd/Makefile
@@ -0,0 +1,1375 @@
+ALL=hostapd hostapd_cli
+CONFIG_FILE = .config
+
+include ../src/build.rules
+
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and
+# nt_password_hash as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_h
+LIBS_h := $(LIBS)
+endif
+ifndef LIBS_n
+LIBS_n := $(LIBS)
+endif
+ifndef LIBS_s
+LIBS_s := $(LIBS)
+endif
+endif
+
+CFLAGS += $(EXTRA_CFLAGS)
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
+
+export BINDIR ?= /usr/local/bin/
+
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../.git),../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+endif
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS += main.o
+OBJS += config_file.o
+
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/preauth_auth.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/bss_load.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
+
+OBJS_c = hostapd_cli.o
+OBJS_c += ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/common/cli.o
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += ../src/drivers/drivers.o
+CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_TAXONOMY
+CFLAGS += -DCONFIG_TAXONOMY
+OBJS += ../src/ap/taxonomy.o
+endif
+
+ifdef CONFIG_MODULE_TESTS
+CFLAGS += -DCONFIG_MODULE_TESTS
+OBJS += hapd_module_tests.o
+endif
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+HOBJS += ../src/utils/trace.o
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD
+LIBS += -lbfd -ldl -liberty -lz
+LIBS_c += -lbfd -ldl -liberty -lz
+LIBS_h += -lbfd -ldl -liberty -lz
+LIBS_n += -lbfd -ldl -liberty -lz
+LIBS_s += -lbfd -ldl -liberty -lz
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_h += -lrt
+LIBS_n += -lrt
+endif
+
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+ifdef CONFIG_ELOOP_EPOLL
+CFLAGS += -DCONFIG_ELOOP_EPOLL
+endif
+
+ifdef CONFIG_ELOOP_KQUEUE
+CFLAGS += -DCONFIG_ELOOP_KQUEUE
+endif
+
+OBJS += ../src/utils/common.o
+OBJS_c += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+OBJS += ../src/common/hw_features_common.o
+
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+
+
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_h += -lgcov
+LIBS_n += -lgcov
+endif
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += ../src/eapol_auth/eapol_auth_dump.o
+endif
+
+ifdef CONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += ../src/ap/accounting.o
+endif
+
+ifdef CONFIG_NO_VLAN
+CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += ../src/ap/vlan_init.o
+OBJS += ../src/ap/vlan_ifconfig.o
+OBJS += ../src/ap/vlan.o
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and VLAN interfaces for the VLAN feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_full.o
+ifdef CONFIG_VLAN_NETLINK
+OBJS += ../src/ap/vlan_util.o
+else
+OBJS += ../src/ap/vlan_ioctl.o
+endif
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+endif
+endif
+endif
+OBJS += ../src/common/ctrl_iface_common.o
+OBJS += ctrl_iface.o
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+ifndef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_HS20
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+endif
+
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
+OBJS += ../src/ap/wpa_auth_ft.o
+NEED_AES_UNWRAP=y
+NEED_AES_SIV=y
+NEED_ETH_P_OUI=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
+ifdef NEED_ETH_P_OUI
+CFLAGS += -DCONFIG_ETH_P_OUI
+OBJS += ../src/ap/eth_p_oui.o
+endif
+
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
+NEED_ECC=y
+NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_AP_MLME=y
+NEED_DRAGONFLY=y
+endif
+
+ifdef CONFIG_OWE
+CFLAGS += -DCONFIG_OWE
+NEED_ECC=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+endif
+
+ifdef CONFIG_AIRTIME_POLICY
+CFLAGS += -DCONFIG_AIRTIME_POLICY
+OBJS += ../src/ap/airtime_policy.o
+endif
+
+ifdef CONFIG_FILS
+CFLAGS += -DCONFIG_FILS
+OBJS += ../src/ap/fils_hlp.o
+NEED_SHA384=y
+NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
+OBJS += ../src/ap/wnm_ap.o
+endif
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
+ifdef CONFIG_IEEE80211AX
+CFLAGS += -DCONFIG_IEEE80211AX
+OBJS += ../src/ap/ieee802_11_he.o
+endif
+
+ifdef CONFIG_MBO
+CFLAGS += -DCONFIG_MBO
+OBJS += ../src/ap/mbo_ap.o
+endif
+
+include ../src/drivers/drivers.mak
+OBJS += $(DRV_AP_OBJS)
+CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_none.o
+endif
+
+
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_HMAC_SHA256_KDF=y
+endif
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_SERVER_MD5
+OBJS += ../src/eap_server/eap_server_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_SERVER_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_SERVER_PEAP
+OBJS += ../src/eap_server/eap_server_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_SERVER_TTLS
+OBJS += ../src/eap_server/eap_server_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += ../src/eap_server/eap_server_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_SERVER_GTC
+OBJS += ../src/eap_server/eap_server_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SERVER_SIM
+OBJS += ../src/eap_server/eap_server_sim.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_SERVER_AKA
+OBJS += ../src/eap_server/eap_server_aka.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementing the interface specified in
+# eap_sim_db.h.
+OBJS += ../src/eap_server/eap_sim_db.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_SERVER_PAX
+OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_SERVER_PSK
+OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SERVER_SAKE
+OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_SERVER_GPSK
+OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_SERVER_PWD
+OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
+NEED_ECC=y
+NEED_DRAGONFLY=y
+endif
+
+ifdef CONFIG_EAP_EKE
+CFLAGS += -DEAP_SERVER_EKE
+OBJS += ../src/eap_server/eap_server_eke.o ../src/eap_common/eap_eke_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += ../src/eap_server/eap_server_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_SERVER_FAST
+OBJS += ../src/eap_server/eap_server_fast.o
+OBJS += ../src/eap_common/eap_fast_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_EAP_TEAP
+CFLAGS += -DEAP_SERVER_TEAP
+OBJS += ../src/eap_server/eap_server_teap.o
+OBJS += ../src/eap_common/eap_teap_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+NEED_DH_GROUPS=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_DPP
+CFLAGS += -DCONFIG_DPP
+OBJS += ../src/common/dpp.o
+OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
+OBJS += ../src/common/dpp_crypto.o
+OBJS += ../src/common/dpp_pkex.o
+OBJS += ../src/common/dpp_reconfig.o
+OBJS += ../src/common/dpp_tcp.o
+OBJS += ../src/ap/dpp_hostapd.o
+OBJS += ../src/ap/gas_query_ap.o
+NEED_AES_SIV=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+NEED_ECC=y
+NEED_JSON=y
+NEED_GAS=y
+NEED_BASE64=y
+NEED_ASN1=y
+ifdef CONFIG_DPP2
+CFLAGS += -DCONFIG_DPP2
+endif
+endif
+
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+CFLAGS += -DEAP_SERVER_TNC
+OBJS += ../src/eap_server/eap_server_tnc.o
+OBJS += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+ifdef CONFIG_MACSEC
+CFLAGS += -DCONFIG_MACSEC
+OBJS += ../src/ap/wpa_auth_kay.o
+OBJS += ../src/pae/ieee802_1x_cp.o
+OBJS += ../src/pae/ieee802_1x_kay.o
+OBJS += ../src/pae/ieee802_1x_key.o
+OBJS += ../src/pae/ieee802_1x_secy_ops.o
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.o
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_server_methods.o
+OBJS += ../src/eap_server/eap_server_identity.o
+CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef NEED_DRAGONFLY
+OBJS += ../src/common/dragonfly.o
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_server_tls_common.o
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+endif
+
+ifeq ($(CONFIG_TLS), wolfssl)
+CONFIG_CRYPTO=wolfssl
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_wolfssl.o
+LIBS += -lwolfssl -lm
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+HOBJS += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_h += -lwolfssl -lm
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+endif
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+CONFIG_CRYPTO=openssl
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_openssl.o
+OBJS += ../src/crypto/tls_openssl_ocsp.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+SOBJS += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+LIBS_n += -lcrypto
+LIBS_s += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+LIBS_s += -ldl
+endif
+ifndef CONFIG_TLS_DEFAULT_CIPHERS
+CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
+endif
+CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_internal.o
+SHA1OBJS += ../src/crypto/sha1-internal.o
+endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+LIBS_n += -lgcrypt
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o
+OBJS += ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+NEED_AES_DEC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), linux)
+OBJS += ../src/crypto/crypto_linux.o
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o
+OBJS += ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DLTM_FAST
+endif
+CONFIG_INTERNAL_DH_GROUP5=y
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_internal.o
+OBJS += ../src/crypto/sha1-internal.o
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-wrap.o
+endif
+endif
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+endif
+ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-unwrap.o
+endif
+endif
+endif
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+endif
+endif
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-dec.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+SHA1OBJS += ../src/crypto/sha1.o
+endif
+endif
+endif
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/md5.o
+endif
+endif
+endif
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += ../src/crypto/md5-internal.o
+HOBJS += ../src/crypto/md5-internal.o
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+ifdef NEED_DES
+CFLAGS += -DCONFIG_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += ../src/crypto/des-internal.o
+endif
+endif
+
+ifdef CONFIG_NO_RC4
+CFLAGS += -DCONFIG_NO_RC4
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+ifndef CONFIG_NO_RC4
+OBJS += ../src/crypto/rc4.o
+endif
+endif
+endif
+
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/sha256.o
+endif
+endif
+endif
+endif
+OBJS += ../src/crypto/sha256-prf.o
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += ../src/crypto/sha384-tlsprf.o
+endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
+ifdef NEED_HMAC_SHA384_KDF
+OBJS += ../src/crypto/sha384-kdf.o
+endif
+ifdef NEED_HMAC_SHA512_KDF
+OBJS += ../src/crypto/sha512-kdf.o
+endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/sha384.o
+endif
+endif
+endif
+endif
+OBJS += ../src/crypto/sha384-prf.o
+endif
+ifdef NEED_SHA512
+CFLAGS += -DCONFIG_SHA512
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/sha512.o
+endif
+endif
+endif
+endif
+OBJS += ../src/crypto/sha512-prf.o
+endif
+
+ifdef CONFIG_INTERNAL_SHA384
+CFLAGS += -DCONFIG_INTERNAL_SHA384
+OBJS += ../src/crypto/sha384-internal.o
+endif
+
+ifdef CONFIG_INTERNAL_SHA512
+CFLAGS += -DCONFIG_INTERNAL_SHA512
+OBJS += ../src/crypto/sha512-internal.o
+endif
+
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
+OBJS += ../src/crypto/random.o
+HOBJS += ../src/crypto/random.o
+HOBJS += ../src/utils/eloop.o
+HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+HOBJS += ../src/crypto/md5.o
+endif
+endif
+endif
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef NEED_JSON
+OBJS += ../src/utils/json.o
+CFLAGS += -DCONFIG_JSON
+endif
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
+CFLAGS += -DNEED_AP_MLME
+endif
+OBJS += ../src/ap/ieee802_11_ht.o
+
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
+ifdef CONFIG_P2P_MANAGER
+CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += ../src/ap/p2p_hostapd.o
+endif
+
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
+endif
+
+ifdef CONFIG_PROXYARP
+CFLAGS += -DCONFIG_PROXYARP
+OBJS += ../src/ap/x_snoop.o
+OBJS += ../src/ap/dhcp_snoop.o
+ifdef CONFIG_IPV6
+OBJS += ../src/ap/ndisc_snoop.o
+endif
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+CFLAGS += -DCONFIG_DEBUG_SYSLOG
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
+ifdef CONFIG_FST
+CFLAGS += -DCONFIG_FST
+OBJS += ../src/fst/fst.o
+OBJS += ../src/fst/fst_group.o
+OBJS += ../src/fst/fst_iface.o
+OBJS += ../src/fst/fst_session.o
+OBJS += ../src/fst/fst_ctrl_aux.o
+ifdef CONFIG_FST_TEST
+CFLAGS += -DCONFIG_FST_TEST
+endif
+ifndef CONFIG_NO_CTRL_IFACE
+OBJS += ../src/fst/fst_ctrl_iface.o
+endif
+endif
+
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+CFLAGS += -DCONFIG_NO_TKIP
+endif
+
+$(DESTDIR)$(BINDIR)/%: %
+ install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
+
+_OBJS_VAR := OBJS
+include ../src/objs.mk
+
+hostapd: $(OBJS)
+ $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
+ @$(E) " LD " $@
+
+ifdef CONFIG_WPA_TRACE
+OBJS_c += ../src/utils/trace.o
+endif
+
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
+
+hostapd_cli: $(OBJS_c)
+ $(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
+ @$(E) " LD " $@
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS)
+NOBJS += ../src/utils/common.o
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+ifndef CONFIG_NO_RC4
+NOBJS += ../src/crypto/rc4.o
+endif
+endif
+endif
+ifdef CONFIG_INTERNAL_MD5
+NOBJS += ../src/crypto/md5-internal.o
+endif
+NOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+NOBJS += ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/utils/wpa_debug.o
+NOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+NOBJS += ../src/utils/trace.o
+endif
+
+HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
+HOBJS += ../src/crypto/aes-encblock.o
+ifdef CONFIG_INTERNAL_AES
+HOBJS += ../src/crypto/aes-internal.o
+HOBJS += ../src/crypto/aes-internal-enc.o
+endif
+ifeq ($(CONFIG_TLS), linux)
+HOBJS += ../src/crypto/crypto_linux.o
+endif
+
+SOBJS += sae_pk_gen.o
+SOBJS += ../src/utils/common.o
+SOBJS += ../src/utils/os_$(CONFIG_OS).o
+SOBJS += ../src/utils/base64.o
+SOBJS += ../src/utils/wpa_debug.o
+SOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+SOBJS += ../src/utils/trace.o
+endif
+SOBJS += ../src/common/ieee802_11_common.o
+SOBJS += ../src/common/sae.o
+SOBJS += ../src/common/sae_pk.o
+SOBJS += ../src/common/dragonfly.o
+SOBJS += $(AESOBJS)
+SOBJS += ../src/crypto/sha256-prf.o
+SOBJS += ../src/crypto/sha384-prf.o
+SOBJS += ../src/crypto/sha512-prf.o
+SOBJS += ../src/crypto/dh_groups.o
+SOBJS += ../src/crypto/sha256-kdf.o
+SOBJS += ../src/crypto/sha384-kdf.o
+SOBJS += ../src/crypto/sha512-kdf.o
+
+_OBJS_VAR := NOBJS
+include ../src/objs.mk
+_OBJS_VAR := HOBJS
+include ../src/objs.mk
+_OBJS_VAR := SOBJS
+include ../src/objs.mk
+
+nt_password_hash: $(NOBJS)
+ $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
+ @$(E) " LD " $@
+
+hlr_auc_gw: $(HOBJS)
+ $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+ @$(E) " LD " $@
+
+sae_pk_gen: $(SOBJS)
+ $(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
+ @$(E) " LD " $@
+
+.PHONY: lcov-html
+lcov-html:
+ lcov -c -d $(BUILDDIR) > lcov.info
+ genhtml lcov.info --output-directory lcov-html
+
+clean: common-clean
+ rm -f core *~ nt_password_hash hlr_auc_gw
+ rm -f sae_pk_gen
+ rm -f lcov.info
+ rm -rf lcov-html
diff --git a/contrib/wpa/hostapd/android.config b/contrib/wpa/hostapd/android.config
new file mode 100644
index 000000000000..c8b3afabef8d
--- /dev/null
+++ b/contrib/wpa/hostapd/android.config
@@ -0,0 +1,214 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+CONFIG_LIBNL20=y
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
+# Broadcom vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_BRCM=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+#CONFIG_RSN_PREAUTH=y
+
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
+# Integrated EAP server
+#CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+#CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+#CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+#CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+#CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+#CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+#CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to Android logcat instead of standard output
+CONFIG_ANDROID_LOG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Remove support for dumping internal state through control interface commands
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Enable AP
+CONFIG_AP=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Multiband Operation support
+# These extensions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
+
+# Include internal line edit mode in hostapd_cli.
+CONFIG_WPA_CLI_EDIT=y
+
+# Opportunistic Wireless Encryption (OWE)
+# Experimental implementation of draft-harkins-owe-07.txt
+#CONFIG_OWE=y
+
+# Wpa_supplicant's random pool is not necessary on Android. Randomness is
+# already provided by the entropymixer service which ensures sufficient
+# entropy is maintained across reboots. Commit b410eb1913 'Initialize
+# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
+# either wpa_supplicant or hostapd are run.
+CONFIG_NO_RANDOM_POOL=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c
index e09e6e141ba4..9bc1dc7756e9 100644
--- a/contrib/wpa/hostapd/config_file.c
+++ b/contrib/wpa/hostapd/config_file.c
@@ -14,6 +14,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
@@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) {
- wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
+ wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19);
user = NULL; /* already in the BSS list */
goto failed;
@@ -711,12 +712,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
@@ -755,6 +754,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ else if (os_strcmp(start, "PASN") == 0)
+ val |= WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -795,6 +798,7 @@ static int hostapd_config_parse_cipher(int line, const char *value)
}
+#ifdef CONFIG_WEP
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
char *val)
{
@@ -845,6 +849,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
return 0;
}
+#endif /* CONFIG_WEP */
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
@@ -942,104 +947,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
}
-/* convert floats with one decimal place to value*10 int, i.e.,
- * "1.5" will return 15 */
-static int hostapd_config_read_int10(const char *value)
-{
- int i, d;
- char *pos;
-
- i = atoi(value);
- pos = os_strchr(value, '.');
- d = 0;
- if (pos) {
- pos++;
- if (*pos >= '0' && *pos <= '9')
- d = *pos - '0';
- }
-
- return i * 10 + d;
-}
-
-
-static int valid_cw(int cw)
-{
- return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
- cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
- cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
- cw == 32767);
-}
-
-
-enum {
- IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
- IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
- IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
- IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
-};
-
-static int hostapd_config_tx_queue(struct hostapd_config *conf,
- const char *name, const char *val)
-{
- int num;
- const char *pos;
- struct hostapd_tx_queue_params *queue;
-
- /* skip 'tx_queue_' prefix */
- pos = name + 9;
- if (os_strncmp(pos, "data", 4) == 0 &&
- pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
- num = pos[4] - '0';
- pos += 6;
- } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
- os_strncmp(pos, "beacon_", 7) == 0) {
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
- return -1;
- }
-
- if (num >= NUM_TX_QUEUES) {
- /* for backwards compatibility, do not trigger failure */
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- }
-
- queue = &conf->tx_queue[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- queue->aifs = atoi(val);
- if (queue->aifs < 0 || queue->aifs > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
- queue->aifs);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmin") == 0) {
- queue->cwmin = atoi(val);
- if (!valid_cw(queue->cwmin)) {
- wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
- queue->cwmin);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmax") == 0) {
- queue->cwmax = atoi(val);
- if (!valid_cw(queue->cwmax)) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
- queue->cwmax);
- return -1;
- }
- } else if (os_strcmp(pos, "burst") == 0) {
- queue->burst = hostapd_config_read_int10(val);
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R_AP
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
@@ -1153,7 +1060,6 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
static int hostapd_config_ht_capab(struct hostapd_config *conf,
const char *capab)
{
@@ -1173,14 +1079,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
}
if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
conf->secondary_channel = 0;
- if (os_strstr(capab, "[SMPS-STATIC]")) {
- conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
- conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
- }
- if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
- conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
- conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
- }
if (os_strstr(capab, "[GF]"))
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
if (os_strstr(capab, "[SHORT-GI-20]"))
@@ -1214,7 +1112,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
return 0;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
@@ -1323,6 +1220,32 @@ static u8 set_he_cap(int val, u8 mask)
return (u8) (mask & (val << find_bit_offset(mask)));
}
+
+static int hostapd_parse_he_srg_bitmap(u8 *bitmap, char *val)
+{
+ int bitpos;
+ char *pos, *end;
+
+ os_memset(bitmap, 0, 8);
+ pos = val;
+ while (*pos != '\0') {
+ end = os_strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ bitpos = atoi(pos);
+ if (bitpos < 0 || bitpos > 64)
+ return -1;
+
+ bitmap[bitpos / 8] |= BIT(bitpos % 8);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_IEEE80211AX */
@@ -2300,6 +2223,35 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->vlan_id = atoi(pos2);
}
+#ifdef CONFIG_SAE_PK
+ pos2 = os_strstr(pos, "|pk=");
+ if (pos2) {
+ const char *epos;
+ char *tmp;
+
+ if (!end)
+ end = pos2;
+ pos2 += 4;
+ epos = os_strchr(pos2, '|');
+ if (epos) {
+ tmp = os_malloc(epos - pos2 + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, pos2, epos - pos2);
+ tmp[epos - pos2] = '\0';
+ } else {
+ tmp = os_strdup(pos2);
+ if (!tmp)
+ goto fail;
+ }
+
+ pw->pk = sae_parse_pk(tmp);
+ str_clear_free(tmp);
+ if (!pw->pk)
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pos2 = os_strstr(pos, "|id=");
if (pos2) {
if (!end)
@@ -2322,6 +2274,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->password[end - val] = '\0';
}
+#ifdef CONFIG_SAE_PK
+ if (pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ !sae_pk_valid_password(pw->password)) {
+ wpa_printf(MSG_INFO,
+ "Invalid SAE password for a SAE-PK sae_password entry");
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
@@ -2329,6 +2293,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
fail:
str_clear_free(pw->password);
os_free(pw->identifier);
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(pw->pk);
+#endif /* CONFIG_SAE_PK */
os_free(pw);
return -1;
}
@@ -2365,6 +2332,22 @@ fail:
#endif /* CONFIG_DPP2 */
+static int get_hex_config(u8 *buf, size_t max_len, int line,
+ const char *field, const char *val)
+{
+ size_t hlen = os_strlen(val), len = hlen / 2;
+ u8 tmp[EXT_CAPA_MAX_LEN];
+
+ os_memset(tmp, 0, EXT_CAPA_MAX_LEN);
+ if (hlen & 1 || len > EXT_CAPA_MAX_LEN || hexstr2bin(val, tmp, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid %s", line, field);
+ return -1;
+ }
+ os_memcpy(buf, tmp, EXT_CAPA_MAX_LEN);
+ return 0;
+}
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2473,6 +2456,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
+ if (pos[0] < 'A' || pos[0] > 'Z' ||
+ pos[1] < 'A' || pos[1] > 'Z') {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid country_code '%s'",
+ line, pos);
+ return 1;
+ }
os_memcpy(conf->country, pos, 2);
} else if (os_strcmp(buf, "country3") == 0) {
conf->country[2] = strtol(pos, NULL, 16);
@@ -2484,12 +2474,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
int eapol_version = atoi(pos);
-
#ifdef CONFIG_MACSEC
- if (eapol_version < 1 || eapol_version > 3) {
+ int max_ver = 3;
#else /* CONFIG_MACSEC */
- if (eapol_version < 1 || eapol_version > 2) {
+ int max_ver = 2;
#endif /* CONFIG_MACSEC */
+
+ if (eapol_version < 1 || eapol_version > max_ver) {
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
line, eapol_version, pos);
@@ -2547,6 +2538,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
bss->tls_flags = parse_tls_flags(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds") == 0) {
+ bss->max_auth_rounds = atoi(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds_short") == 0) {
+ bss->max_auth_rounds_short = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@@ -2611,7 +2606,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos);
- if (val < 0 || val > 1) {
+ if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value",
line);
@@ -2620,6 +2615,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->eap_teap_auth = val;
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
bss->eap_teap_pac_no_inner = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
+ bss->eap_teap_separate_result = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_id") == 0) {
+ bss->eap_teap_id = atoi(pos);
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
@@ -2668,6 +2667,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "erp_domain") == 0) {
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
int val = atoi(pos);
@@ -2695,6 +2695,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, bss->wep_rekeying_period);
return 1;
}
+#endif /* CONFIG_WEP */
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
bss->eap_reauth_period = atoi(pos);
if (bss->eap_reauth_period < 0) {
@@ -2706,8 +2707,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (os_strcmp(buf, "iapp_interface") == 0) {
- bss->ieee802_11f = 1;
- os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
+ wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
#endif /* CONFIG_IAPP */
} else if (os_strcmp(buf, "own_ip_addr") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
@@ -2728,6 +2728,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
bss->radius->force_client_addr = 1;
+ } else if (os_strcmp(buf, "radius_client_dev") == 0) {
+ os_free(bss->radius->force_client_dev);
+ bss->radius->force_client_dev = os_strdup(pos);
} else if (os_strcmp(buf, "auth_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
&bss->radius->auth_servers,
@@ -2870,6 +2873,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "wpa") == 0) {
bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "extended_key_id") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid extended_key_id=%d; allowed range 0..2",
+ line, val);
+ return 1;
+ }
+ bss->extended_key_id = val;
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1;
@@ -2879,6 +2892,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
+ bss->wpa_deny_ptk0_rekey = atoi(pos);
+ if (bss->wpa_deny_ptk0_rekey < 0 ||
+ bss->wpa_deny_ptk0_rekey > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
+ line, bss->wpa_deny_ptk0_rekey);
+ return 1;
+ }
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
char *endp;
unsigned long val = strtoul(pos, &endp, 0);
@@ -3131,6 +3153,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
conf->acs_exclude_dfs = atoi(pos);
+ } else if (os_strcmp(buf, "op_class") == 0) {
+ conf->op_class = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@@ -3145,12 +3169,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
+ } else if (os_strcmp(buf, "edmg_channel") == 0) {
+ conf->edmg_channel = atoi(pos);
+ } else if (os_strcmp(buf, "enable_edmg") == 0) {
+ conf->enable_edmg = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
}
+ } else if (os_strcmp(buf, "freqlist") == 0) {
+ if (freq_range_list_parse(&conf->acs_freq_list, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid frequency list",
+ line);
+ return 1;
+ }
+ conf->acs_freq_list_present = 1;
+ } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
+ conf->acs_exclude_6ghz_non_psc = atoi(pos);
} else if (os_strcmp(buf, "beacon_int") == 0) {
int val = atoi(pos);
/* MIB defines range as 1..65535, but very small values
@@ -3272,6 +3309,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
conf->rate_type = BEACON_RATE_VHT;
conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "he:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 11) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HE-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HE;
+ conf->beacon_rate = val;
} else {
val = atoi(pos);
if (val < 10 || val > 10000) {
@@ -3292,6 +3339,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
bss->no_probe_resp_if_max_sta = atoi(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@@ -3310,6 +3358,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, buf);
return 1;
}
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
@@ -3341,7 +3390,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
conf->ap_table_expiration_time = atoi(pos);
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
- if (hostapd_config_tx_queue(conf, buf, pos)) {
+ if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
line);
return 1;
@@ -3372,7 +3421,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
conf->use_driver_iface_addr = atoi(pos);
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
@@ -3389,6 +3437,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_prot") == 0) {
+ bss->beacon_prot = atoi(pos);
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) {
@@ -3403,14 +3453,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
} else if (os_strcmp(buf, "ocv") == 0) {
bss->ocv = atoi(pos);
if (bss->ocv && !bss->ieee80211w)
bss->ieee80211w = 1;
#endif /* CONFIG_OCV */
-#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
} else if (os_strcmp(buf, "ht_capab") == 0) {
@@ -3423,7 +3471,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->require_ht = atoi(pos);
} else if (os_strcmp(buf, "obss_interval") == 0) {
conf->obss_interval = atoi(pos);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
} else if (os_strcmp(buf, "ieee80211ac") == 0) {
conf->ieee80211ac = atoi(pos);
@@ -3456,11 +3503,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
conf->he_phy_capab.he_mu_beamformer = atoi(pos);
} else if (os_strcmp(buf, "he_bss_color") == 0) {
- conf->he_op.he_bss_color = atoi(pos);
+ conf->he_op.he_bss_color = atoi(pos) & 0x3f;
+ conf->he_op.he_bss_color_disabled = 0;
+ } else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
+ conf->he_op.he_bss_color_partial = atoi(pos);
} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
conf->he_op.he_default_pe_duration = atoi(pos);
} else if (os_strcmp(buf, "he_twt_required") == 0) {
conf->he_op.he_twt_required = atoi(pos);
+ } else if (os_strcmp(buf, "he_twt_responder") == 0) {
+ conf->he_op.he_twt_responder = atoi(pos);
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
conf->he_op.he_rts_threshold = atoi(pos);
} else if (os_strcmp(buf, "he_basic_mcs_nss_set") == 0) {
@@ -3550,19 +3602,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
atoi(pos) & 0xff;
} else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
- conf->spr.sr_control = atoi(pos) & 0xff;
+ conf->spr.sr_control = atoi(pos) & 0x1f;
} else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
conf->spr.srg_obss_pd_min_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
conf->spr.srg_obss_pd_max_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_spr_srg_bss_colors") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_bss_color_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg bss colors list '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "he_spr_srg_partial_bssid") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_partial_bssid_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg partial bssid list '%s'",
+ line, pos);
+ return 1;
+ }
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
conf->he_oper_chwidth = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
conf->he_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
conf->he_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_mpdu") == 0) {
+ conf->he_6ghz_max_mpdu = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_ampdu_len_exp") == 0) {
+ conf->he_6ghz_max_ampdu_len_exp = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_rx_ant_pat") == 0) {
+ conf->he_6ghz_rx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_tx_ant_pat") == 0) {
+ conf->he_6ghz_tx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "unsol_bcast_probe_resp_interval") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 20) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid unsol_bcast_probe_resp_interval value",
+ line);
+ return 1;
+ }
+ bss->unsol_bcast_probe_resp_interval = val;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -3744,6 +3830,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "server_id") == 0) {
os_free(bss->server_id);
bss->server_id = os_strdup(pos);
+ } else if (os_strcmp(buf, "wps_application_ext") == 0) {
+ wpabuf_free(bss->wps_application_ext);
+ bss->wps_application_ext = wpabuf_parse_bin(pos);
#ifdef CONFIG_WPS_NFC
} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
bss->wps_nfc_dev_pw_id = atoi(pos);
@@ -4144,9 +4233,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
+ } else if (os_strcmp(buf, "sae_commit_status") == 0) {
+ bss->sae_commit_status = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pk_omit") == 0) {
+ bss->sae_pk_omit = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pk_password_check_skip") == 0) {
+ bss->sae_pk_password_check_skip = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
+ wpabuf_free(bss->rsne_override_eapol);
+ bss->rsne_override_eapol = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
+ wpabuf_free(bss->rsnxe_override_eapol);
+ bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsne_override_ft") == 0) {
+ wpabuf_free(bss->rsne_override_ft);
+ bss->rsne_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
+ wpabuf_free(bss->rsnxe_override_ft);
+ bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
+ wpabuf_free(bss->gtk_rsc_override);
+ bss->gtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
+ wpabuf_free(bss->igtk_rsc_override);
+ bss->igtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
+ bss->no_beacon_rsnxe = atoi(pos);
+ } else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
+ bss->skip_prune_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
+ bss->ft_rsnxe_used = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) {
+ bss->oci_freq_override_eapol_m3 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) {
+ bss->oci_freq_override_eapol_g1 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) {
+ bss->oci_freq_override_saquery_req = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) {
+ bss->oci_freq_override_saquery_resp = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) {
+ bss->oci_freq_override_ft_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) {
+ bss->oci_freq_override_fils_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
+ bss->oci_freq_override_wnm_sleep = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4162,8 +4295,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "assocresp_elements") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
return 1;
- } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
- bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0 ||
+ os_strcmp(buf, "anti_clogging_threshold") == 0) {
+ bss->anti_clogging_threshold = atoi(pos);
} else if (os_strcmp(buf, "sae_sync") == 0) {
bss->sae_sync = atoi(pos);
} else if (os_strcmp(buf, "sae_groups") == 0) {
@@ -4175,6 +4309,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
bss->sae_require_mfp = atoi(pos);
+ } else if (os_strcmp(buf, "sae_confirm_immediate") == 0) {
+ bss->sae_confirm_immediate = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pwe") == 0) {
+ bss->sae_pwe = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@@ -4318,12 +4456,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->dhcp_server_port = atoi(pos);
} else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
bss->dhcp_relay_port = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) {
+ bss->fils_discovery_min_int = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) {
+ bss->fils_discovery_max_int = atoi(pos);
#endif /* CONFIG_FILS */
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
bss->multicast_to_unicast = atoi(pos);
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
+ } else if (os_strcmp(buf, "notify_mgmt_frames") == 0) {
+ bss->notify_mgmt_frames = atoi(pos);
#ifdef CONFIG_DPP
+ } else if (os_strcmp(buf, "dpp_name") == 0) {
+ os_free(bss->dpp_name);
+ bss->dpp_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_mud_url") == 0) {
+ os_free(bss->dpp_mud_url);
+ bss->dpp_mud_url = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
@@ -4339,6 +4489,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
+ } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
+ bss->dpp_configurator_connectivity = atoi(pos);
+ } else if (os_strcmp(buf, "dpp_pfs") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid dpp_pfs value '%s'",
+ line, pos);
+ return -1;
+ }
+ bss->dpp_pfs = val;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@@ -4372,9 +4534,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
+ bss->owe_ptk_workaround = atoi(pos);
+#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
bss->coloc_intf_reporting = atoi(pos);
-#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "multi_ap") == 0) {
int val = atoi(pos);
@@ -4389,8 +4553,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_rssi = atoi(pos);
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) {
+ conf->rssi_ignore_probe_request = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
+ } else if (os_strcmp(buf, "transition_disable") == 0) {
+ bss->transition_disable = strtol(pos, NULL, 16);
#ifdef CONFIG_AIRTIME_POLICY
} else if (os_strcmp(buf, "airtime_mode") == 0) {
int val = atoi(pos);
@@ -4506,6 +4674,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */
+ } else if (os_strcmp(buf, "disable_11n") == 0) {
+ bss->disable_11n = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ac") == 0) {
+ bss->disable_11ac = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ax") == 0) {
+ bss->disable_11ax = !!atoi(pos);
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
+ bss->force_kdk_derivation = atoi(pos);
+ } else if (os_strcmp(buf, "pasn_corrupt_mic") == 0) {
+ bss->pasn_corrupt_mic = atoi(pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+ } else if (os_strcmp(buf, "pasn_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->pasn_groups, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid pasn_groups value '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
+ bss->pasn_comeback_after = atoi(pos);
+#endif /* CONFIG_PASN */
+ } else if (os_strcmp(buf, "ext_capa_mask") == 0) {
+ if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN,
+ line, "ext_capa_mask", pos))
+ return 1;
+ } else if (os_strcmp(buf, "ext_capa") == 0) {
+ if (get_hex_config(bss->ext_capa, EXT_CAPA_MAX_LEN,
+ line, "ext_capa", pos))
+ return 1;
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c
index 0f6dfa13d8f3..4a2d60627070 100644
--- a/contrib/wpa/hostapd/ctrl_iface.c
+++ b/contrib/wpa/hostapd/ctrl_iface.c
@@ -11,7 +11,11 @@
#ifndef CONFIG_NATIVE_WINDOWS
#ifdef CONFIG_TESTING_OPTIONS
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#else
#include <net/ethernet.h>
+#endif
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
@@ -33,6 +37,7 @@
#include "common/dpp.h"
#endif /* CONFIG_DPP */
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -43,6 +48,7 @@
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h"
+#include "ap/pmksa_cache_auth.h"
#include "ap/ieee802_11.h"
#include "ap/sta_info.h"
#include "ap/wps_hostapd.h"
@@ -55,6 +61,7 @@
#include "ap/neighbor_db.h"
#include "ap/rrm.h"
#include "ap/dpp_hostapd.h"
+#include "ap/dfs.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -65,9 +72,6 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
#ifdef CONFIG_CTRL_IFACE_UDP
-#define COOKIE_LEN 8
-static unsigned char cookie[COOKIE_LEN];
-static unsigned char gcookie[COOKIE_LEN];
#define HOSTAPD_CTRL_IFACE_PORT 8877
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
@@ -130,7 +134,6 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
}
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
@@ -149,7 +152,6 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
return 0;
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1098,7 +1100,6 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
if (os_snprintf_error(end - pos, ret))
@@ -1111,7 +1112,6 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, "SAE ");
@@ -1223,6 +1223,52 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+
+ if (hapd->conf->multi_ap) {
+ struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
+
+ ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
+ hapd->conf->multi_ap);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ if (ssid->ssid_len) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_ssid=%s\n",
+ wpa_ssid_txt(ssid->ssid,
+ ssid->ssid_len));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_passphrase) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_passphrase=%s\n",
+ ssid->wpa_passphrase);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_psk &&
+ ssid->wpa_psk->group) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
+ PMK_LEN);
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_psk=%s\n",
+ hex);
+ forced_memzero(hex, sizeof(hex));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ }
#endif /* CONFIG_WPS */
if (hapd->conf->wpa) {
@@ -1290,6 +1336,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
pos += ret;
}
+ if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
+ ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
+ hapd->conf->wpa_deny_ptk0_rekey);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
+ ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
+ hapd->conf->extended_key_id);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
return pos - buf;
}
@@ -1330,6 +1392,41 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
}
}
+
+static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
+ const char *bands)
+{
+ union wpa_event_data event;
+ u32 setband_mask = WPA_SETBAND_AUTO;
+
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
+
+ if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
+ os_memset(&event, 0, sizeof(event));
+ event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
+ wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event);
+ }
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
{
char *value;
@@ -1372,6 +1469,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->ext_mgmt_frame_handling = atoi(value);
} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
hapd->ext_eapol_frame_io = atoi(value);
+ } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) {
+ hapd->force_backlog_bytes = atoi(value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(hapd->dpp_config_obj_override);
@@ -1387,6 +1486,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
dpp_test = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
+ dpp_version_override = atoi(value);
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -1412,7 +1513,19 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
+ hapd->dpp_init_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
+ hapd->dpp_init_retry_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
+ hapd->dpp_resp_wait_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+ hapd->dpp_resp_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+ hapd->dpp_resp_retry_time = atoi(value);
#endif /* CONFIG_DPP */
+ } else if (os_strcasecmp(cmd, "setband") == 0) {
+ ret = hostapd_ctrl_iface_set_band(hapd, value);
} else {
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
@@ -1428,7 +1541,37 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
if (ieee802_11_update_beacons(hapd->iface))
wpa_printf(MSG_DEBUG,
"Failed to update beacons with WMM parameters");
+ } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
+ os_strcmp(cmd, "sae_password") == 0 ||
+ os_strcmp(cmd, "sae_pwe") == 0) {
+ if (hapd->started)
+ hostapd_setup_sae_pt(hapd->conf);
+ } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
+ wpa_auth_set_transition_disable(hapd->wpa_auth,
+ hapd->conf->transition_disable);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
+ wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
+ hapd->conf->ft_rsnxe_used);
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
+#endif /* CONFIG_TESTING_OPTIONS */
}
return ret;
@@ -1628,7 +1771,7 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
return -1;
}
- res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+ res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
os_free(buf);
return res;
}
@@ -1803,6 +1946,52 @@ static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
}
+static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd)
+{
+ char *pos, *pos2;
+ u8 dst[ETH_ALEN], *buf;
+ int used, ret;
+ size_t len;
+ unsigned int prev;
+ int encrypt = 0;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2) {
+ len = pos2 - pos;
+ encrypt = os_strstr(pos2, "encrypt=1") != NULL;
+ } else {
+ len = os_strlen(pos);
+ }
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (!buf || hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ prev = hapd->ext_eapol_frame_io;
+ hapd->ext_eapol_frame_io = 0;
+ ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt);
+ hapd->ext_eapol_frame_io = prev;
+ os_free(buf);
+
+ return ret;
+}
+
+
static u16 ipv4_hdr_checksum(const void *buf, size_t len)
{
size_t i;
@@ -1827,7 +2016,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip ip;
const u8 *pos;
unsigned int i;
char extra[30];
@@ -1843,14 +2032,14 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
- if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ if (ip.ip_hl != 5 || ip.ip_v != 4 ||
+ ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
- "test data: RX - ignore unexpect IP header");
+ "test data: RX - ignore unexpected IP header");
return;
}
- for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
@@ -1860,8 +2049,8 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
}
extra[0] = '\0';
- if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
- os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -1914,7 +2103,7 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
@@ -1953,17 +2142,17 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- ip->tot_len = htons(send_len);
- ip->protocol = 1;
- ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
- ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
- ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
@@ -2109,7 +2298,32 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hwaddr_aton(cmd, addr))
return -1;
-#ifdef CONFIG_IEEE80211W
+ if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
+ if (hapd->last_bigtk_alg == WPA_ALG_NONE)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
+
+ /* First, use a zero key to avoid any possible duplicate key
+ * avoidance in the driver. */
+ if (hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_bigtk_alg,
+ broadcast_ether_addr,
+ hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_bigtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ return -1;
+
+ /* Set the previously configured key to reset its TSC */
+ return hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_bigtk_alg,
+ broadcast_ether_addr,
+ hapd->last_bigtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_bigtk,
+ hapd->last_bigtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
+ }
+
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1;
@@ -2121,19 +2335,20 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- zero, hapd->last_igtk_len) < 0)
+ hapd->last_igtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- hapd->last_igtk,
- hapd->last_igtk_len);
+ hapd->last_igtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_igtk,
+ hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
-#endif /* CONFIG_IEEE80211W */
if (is_broadcast_ether_addr(addr)) {
if (hapd->last_gtk_alg == WPA_ALG_NONE)
@@ -2146,16 +2361,19 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- zero, hapd->last_gtk_len) < 0)
+ hapd->last_gtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- hapd->last_gtk, hapd->last_gtk_len);
+ hapd->last_gtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_gtk,
+ hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
sta = ap_get_sta(hapd, addr);
@@ -2171,14 +2389,16 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
/* First, use a zero key to avoid any possible duplicate key avoidance
* in the driver. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- zero, sta->last_tk_len) < 0)
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ zero, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
+ 0, sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2187,11 +2407,12 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
u8 addr[ETH_ALEN];
const char *pos = cmd;
enum wpa_alg alg;
+ enum key_flag key_flag;
int idx, set_tx;
u8 seq[6], key[WPA_TK_MAX_LEN];
size_t key_len;
- /* parameters: alg addr idx set_tx seq key */
+ /* parameters: alg addr idx set_tx seq key key_flag */
alg = atoi(pos);
pos = os_strchr(pos, ' ');
@@ -2220,13 +2441,24 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
if (*pos != ' ')
return -1;
pos++;
- key_len = os_strlen(pos) / 2;
+ if (!os_strchr(pos, ' '))
+ return -1;
+ key_len = (os_strchr(pos, ' ') - pos) / 2;
if (hexstr2bin(pos, key, key_len) < 0)
return -1;
+ pos += 2 * key_len;
+ if (*pos != ' ')
+ return -1;
+
+ pos++;
+ key_flag = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ return -1;
wpa_printf(MSG_INFO, "TESTING: Set key");
- return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
- set_tx, seq, 6, key, key_len);
+ return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
+ set_tx, seq, 6, key, key_len, key_flag);
}
@@ -2241,8 +2473,9 @@ static void restore_tk(void *ctx1, void *ctx2)
* in replay protection issues for now since there is no clean way of
* preventing encryption of a single EAPOL frame. */
hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2265,8 +2498,8 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2295,8 +2528,8 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2325,8 +2558,8 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO,
@@ -2336,26 +2569,268 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
plain ? restore_tk : NULL, hapd, sta);
}
+
+static int hostapd_ctrl_rekey_ptk(struct hostapd_data *hapd, const char *cmd)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm);
+}
+
+
+static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
+ char *buf, size_t buflen)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
+ if (!pmksa)
+ return -1;
+
+ return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
+}
+
+
+static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
+ char *buf, size_t buflen)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ const u8 *pmk;
+ int pmk_len;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
+ MAC2STR(addr));
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
+ }
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk || !pmk_len) {
+ wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
+ MAC2STR(addr));
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
+ }
+
+ return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
+}
+
+
+static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u16 type;
+ char *pos, *end;
+ u8 match[10];
+ size_t match_len;
+ bool multicast = false;
+
+ type = strtol(cmd, &pos, 16);
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ end = os_strchr(pos, ' ');
+ if (end) {
+ match_len = end - pos;
+ multicast = os_strstr(end, "multicast") != NULL;
+ } else {
+ match_len = os_strlen(pos) / 2;
+ }
+ if (hexstr2bin(pos, match, match_len))
+ return -1;
+
+ return hostapd_drv_register_frame(hapd, type, match, match_len,
+ multicast);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
+{
+ switch (params->bandwidth) {
+ case 0:
+ /* bandwidth not specified: use 20 MHz by default */
+ /* fall-through */
+ case 20:
+ if (params->center_freq1 &&
+ params->center_freq1 != params->freq)
+ return -1;
+
+ if (params->center_freq2 || params->sec_channel_offset)
+ return -1;
+ break;
+ case 40:
+ if (params->center_freq2 || !params->sec_channel_offset)
+ return -1;
+
+ if (!params->center_freq1)
+ break;
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 10 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq - 10 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 80:
+ if (!params->center_freq1 || !params->sec_channel_offset)
+ return 1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq - 10 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1)
+ return 1;
+ break;
+ case -1:
+ if (params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Adjacent and overlapped are not allowed for 80+80 */
+ if (params->center_freq2 &&
+ params->center_freq1 - params->center_freq2 <= 80 &&
+ params->center_freq2 - params->center_freq1 <= 80)
+ return 1;
+ break;
+ case 160:
+ if (!params->center_freq1 || params->center_freq2 ||
+ !params->sec_channel_offset)
+ return -1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 70 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1 &&
+ params->freq - 10 != params->center_freq1 &&
+ params->freq - 50 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq + 50 != params->center_freq1 &&
+ params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1 &&
+ params->freq - 70 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* NEED_AP_MLME */
+
+
static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
char *pos)
{
#ifdef NEED_AP_MLME
struct csa_settings settings;
int ret;
+ int dfs_range = 0;
unsigned int i;
+ int bandwidth;
+ u8 chan;
ret = hostapd_parse_csa_settings(pos, &settings);
if (ret)
return ret;
+ ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "chanswitch: invalid frequency settings provided");
+ return ret;
+ }
+
+ switch (settings.freq_params.bandwidth) {
+ case 40:
+ bandwidth = CHAN_WIDTH_40;
+ break;
+ case 80:
+ if (settings.freq_params.center_freq2)
+ bandwidth = CHAN_WIDTH_80P80;
+ else
+ bandwidth = CHAN_WIDTH_80;
+ break;
+ case 160:
+ bandwidth = CHAN_WIDTH_160;
+ break;
+ default:
+ bandwidth = CHAN_WIDTH_20;
+ break;
+ }
+
+ if (settings.freq_params.center_freq1)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq1);
+ else
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.freq);
+
+ if (settings.freq_params.center_freq2)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq2);
+
+ if (dfs_range) {
+ ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
+ if (ret == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR,
+ "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth);
+ return -1;
+ }
+
+ settings.freq_params.channel = chan;
+
+ wpa_printf(MSG_DEBUG,
+ "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
+ settings.freq_params.channel,
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth,
+ settings.freq_params.center_freq1);
+
+ /* Perform CAC and switch channel */
+ hostapd_switch_channel_fallback(iface, &settings.freq_params);
+ return 0;
+ }
+
for (i = 0; i < iface->num_bss; i++) {
- /* Save CHAN_SWITCH VHT config */
- hostapd_chan_switch_vht_config(
- iface->bss[i], settings.freq_params.vht_enabled);
+ /* Save CHAN_SWITCH VHT and HE config */
+ hostapd_chan_switch_config(iface->bss[i],
+ &settings.freq_params);
ret = hostapd_switch_channel(iface->bss[i], &settings);
if (ret) {
@@ -2389,13 +2864,17 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
char *buf, size_t buflen)
{
int ret;
- char *pos;
+ char *pos, *temp = NULL;
u8 *data = NULL;
unsigned int vendor_id, subcmd;
+ enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply;
size_t data_len = 0;
- /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ /**
+ * cmd: <vendor id> <subcommand id> [<hex formatted data>]
+ * [nested=<0|1>]
+ */
vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos))
return -EINVAL;
@@ -2405,7 +2884,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
if (*pos != '\0') {
if (!isblank((unsigned char) *pos++))
return -EINVAL;
- data_len = os_strlen(pos);
+
+ temp = os_strchr(pos, ' ');
+ data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
}
if (data_len) {
@@ -2422,6 +2903,11 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
}
+ pos = os_strstr(cmd, "nested=");
+ if (pos)
+ nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
+ NESTED_ATTR_NOT_USED;
+
reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) {
os_free(data);
@@ -2429,7 +2915,7 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
- reply);
+ nested_attr_flag, reply);
if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
@@ -2679,6 +3165,20 @@ static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
}
+static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ return hostapd_neighbor_show(hapd, buf, buflen);
+}
+
+
static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
{
struct wpa_ssid_value ssid;
@@ -2785,6 +3285,7 @@ static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
char *buf)
{
struct wpa_ssid_value ssid;
+ struct wpa_ssid_value *ssidp = NULL;
u8 bssid[ETH_ALEN];
char *tmp;
@@ -2794,13 +3295,16 @@ static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
}
tmp = os_strstr(buf, "ssid=");
- if (!tmp || ssid_parse(tmp + 5, &ssid)) {
- wpa_printf(MSG_ERROR,
- "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
- return -1;
+ if (tmp) {
+ ssidp = &ssid;
+ if (ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBOR: Bad SSID");
+ return -1;
+ }
}
- return hostapd_neighbor_remove(hapd, bssid, &ssid);
+ return hostapd_neighbor_remove(hapd, bssid, ssidp);
}
@@ -2832,6 +3336,34 @@ static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
}
+static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags2);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags2 & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag2_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr)
{
@@ -2934,6 +3466,23 @@ static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
}
+#ifdef ANDROID
+static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen);
+ if (ret == 0) {
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ if (os_snprintf_error(buflen, ret))
+ ret = -1;
+ }
+ return ret;
+}
+#endif /* ANDROID */
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -3032,13 +3581,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
@@ -3150,6 +3697,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) {
+ if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
reply_len = -1;
@@ -3185,9 +3735,18 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "REKEY_PTK ", 10) == 0) {
+ if (hostapd_ctrl_rekey_ptk(hapd, buf + 10) < 0)
+ reply_len = -1;
} else if (os_strcmp(buf, "REKEY_GTK") == 0) {
if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
+ reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) {
+ if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -3225,6 +3784,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
reply_len = -1;
+ } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) {
+ reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply,
+ reply_size);
} else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
reply_len = -1;
@@ -3240,20 +3802,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
+ reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
+ reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_add_mac(
+ if (hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19))
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac, buf + 19))
hostapd_disassoc_accept_mac(hapd);
else
reply_len = -1;
- } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19);
} else if (os_strcmp(buf + 11, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->accept_mac,
@@ -3262,6 +3828,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac);
+ hostapd_disassoc_accept_mac(hapd);
}
} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
@@ -3269,10 +3836,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
&hapd->conf->deny_mac,
&hapd->conf->num_deny_mac, buf + 17))
hostapd_disassoc_deny_mac(hapd);
+ else
+ reply_len = -1;
} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17);
+ if (hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17))
+ reply_len = -1;
} else if (os_strcmp(buf + 9, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->deny_mac,
@@ -3292,6 +3862,33 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
+ res = hostapd_dpp_nfc_uri(hapd, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
if (res < 0) {
@@ -3321,6 +3918,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
+ atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1;
@@ -3364,6 +3966,21 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1;
+#ifdef CONFIG_DPP2
+ } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
+ if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
+ if (hostapd_dpp_controller_start(hapd, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
+ dpp_controller_stop(hapd->iface->interfaces->dpp);
+ } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+ if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+ hostapd_dpp_chirp_stop(hapd);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef RADIUS_SERVER
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
@@ -3373,6 +3990,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
reply_len = hostapd_ctrl_iface_get_capability(
hapd, buf + 15, reply, reply_size);
+#ifdef CONFIG_PASN
+ } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
+ reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
+#endif /* CONFIG_PASN */
+#ifdef ANDROID
+ } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
+ reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
+ reply_size);
+#endif /* ANDROID */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -3400,7 +4026,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
int level = MSG_DEBUG;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -3425,28 +4051,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- cookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ hapd->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto done;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- pos = buf + 7 + 2 * COOKIE_LEN;
+ pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*pos == ' ')
pos++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -3535,7 +4163,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
dl_list_init(&hapd->ctrl_dst);
hapd->ctrl_sock = -1;
- os_get_random(cookie, COOKIE_LEN);
+ os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -3849,6 +4477,11 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
#ifdef CONFIG_TESTING_OPTIONS
#ifdef CONFIG_DPP
dpp_test = DPP_TEST_DISABLED;
+#ifdef CONFIG_DPP2
+ dpp_version_override = 2;
+#else /* CONFIG_DPP2 */
+ dpp_version_override = 1;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
@@ -4114,7 +4747,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
- void *interfaces = eloop_ctx;
+ struct hapd_interfaces *interfaces = eloop_ctx;
char buffer[256], *buf = buffer;
int res;
struct sockaddr_storage from;
@@ -4123,7 +4756,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
const int reply_size = 4096;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
@@ -4152,28 +4785,30 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- gcookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ interfaces->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto send_reply;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- buf += 7 + 2 * COOKIE_LEN;
+ buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*buf == ' ')
buf++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -4317,7 +4952,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
}
}
- os_get_random(gcookie, COOKIE_LEN);
+ os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -4367,6 +5002,8 @@ try_again:
return -1;
}
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
return 0;
fail:
@@ -4469,6 +5106,8 @@ fail:
eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
interface, NULL);
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
return 0;
fail:
@@ -4538,37 +5177,43 @@ static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
}
-static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
- enum wpa_msg_type type,
- const char *buf, size_t len)
+static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
+ const char *ifname, int level,
+ const char *buf, size_t len)
{
struct wpa_ctrl_dst *dst, *next;
- struct dl_list *ctrl_dst;
struct msghdr msg;
- int idx;
- struct iovec io[2];
+ int idx, res;
+ struct iovec io[5];
char levelstr[10];
- int s;
- if (type != WPA_MSG_ONLY_GLOBAL) {
- s = hapd->ctrl_sock;
- ctrl_dst = &hapd->ctrl_dst;
- } else {
- s = hapd->iface->interfaces->global_ctrl_sock;
- ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
- }
-
- if (s < 0 || dl_list_empty(ctrl_dst))
+ if (sock < 0 || dl_list_empty(ctrl_dst))
return;
- os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
- io[0].iov_base = levelstr;
- io[0].iov_len = os_strlen(levelstr);
- io[1].iov_base = (char *) buf;
- io[1].iov_len = len;
+ res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ if (os_snprintf_error(sizeof(levelstr), res))
+ return;
+ idx = 0;
+ if (ifname) {
+ io[idx].iov_base = "IFNAME=";
+ io[idx].iov_len = 7;
+ idx++;
+ io[idx].iov_base = (char *) ifname;
+ io[idx].iov_len = os_strlen(ifname);
+ idx++;
+ io[idx].iov_base = " ";
+ io[idx].iov_len = 1;
+ idx++;
+ }
+ io[idx].iov_base = levelstr;
+ io[idx].iov_len = os_strlen(levelstr);
+ idx++;
+ io[idx].iov_base = (char *) buf;
+ io[idx].iov_len = len;
+ idx++;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
- msg.msg_iovlen = 2;
+ msg.msg_iovlen = idx;
idx = 0;
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
@@ -4578,22 +5223,16 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
&dst->addr, dst->addrlen);
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
- if (sendmsg(s, &msg, 0) < 0) {
+ if (sendmsg(sock, &msg, 0) < 0) {
int _errno = errno;
wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
"%d - %s",
idx, errno, strerror(errno));
dst->errors++;
if (dst->errors > 10 || _errno == ENOENT) {
- if (type != WPA_MSG_ONLY_GLOBAL)
- hostapd_ctrl_iface_detach(
- hapd, &dst->addr,
- dst->addrlen);
- else
- hostapd_global_ctrl_iface_detach(
- hapd->iface->interfaces,
- &dst->addr,
- dst->addrlen);
+ ctrl_iface_detach(ctrl_dst,
+ &dst->addr,
+ dst->addrlen);
}
} else
dst->errors = 0;
@@ -4602,4 +5241,25 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
}
}
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ enum wpa_msg_type type,
+ const char *buf, size_t len)
+{
+ if (type != WPA_MSG_NO_GLOBAL) {
+ hostapd_ctrl_iface_send_internal(
+ hapd->iface->interfaces->global_ctrl_sock,
+ &hapd->iface->interfaces->global_ctrl_dst,
+ type != WPA_MSG_PER_INTERFACE ?
+ NULL : hapd->conf->iface,
+ level, buf, len);
+ }
+
+ if (type != WPA_MSG_ONLY_GLOBAL) {
+ hostapd_ctrl_iface_send_internal(
+ hapd->ctrl_sock, &hapd->ctrl_dst,
+ NULL, level, buf, len);
+ }
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig
index 01871c951f3d..666447e4ab40 100644
--- a/contrib/wpa/hostapd/defconfig
+++ b/contrib/wpa/hostapd/defconfig
@@ -44,15 +44,9 @@ CONFIG_LIBNL32=y
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -154,9 +148,6 @@ CONFIG_IPV6=y
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
-# IEEE 802.11n (High Throughput) support
-#CONFIG_IEEE80211N=y
-
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
@@ -355,12 +346,12 @@ CONFIG_IPV6=y
# * ath10k
#
# For more details refer to:
-# http://wireless.kernel.org/en/users/Documentation/acs
+# https://wireless.wiki.kernel.org/en/users/documentation/acs
#
#CONFIG_ACS=y
# Multiband Operation support
-# These extentions facilitate efficient use of multiple frequency bands
+# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
@@ -389,3 +380,25 @@ CONFIG_IPV6=y
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
+# Remove all TKIP functionality
+# TKIP is an old cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used anymore. For now, the default hostapd
+# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
+# that functionality is subject to be removed in the future.
+#CONFIG_NO_TKIP=y
+
+# Pre-Association Security Negotiation (PASN)
+# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
+# design is still subject to change. As such, this should not yet be enabled in
+# production use.
+# This requires CONFIG_IEEE80211W=y to be enabled, too.
+#CONFIG_PASN=y
diff --git a/contrib/wpa/hostapd/hostapd.android.rc b/contrib/wpa/hostapd/hostapd.android.rc
new file mode 100644
index 000000000000..26a87b808914
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.android.rc
@@ -0,0 +1,19 @@
+#
+# init.rc fragment for hostapd on Android
+# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+on post-fs-data
+ mkdir /data/misc/wifi/hostapd 0770 wifi wifi
+
+service hostapd /vendor/bin/hostapd \
+ /data/misc/wifi/hostapd.conf
+ class main
+ user wifi
+ writepid /data/misc/wifi/hostapd.pid
+ group wifi
+ disabled
+ oneshot
diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf
index ce3ecdddf157..b5d15061f850 100644
--- a/contrib/wpa/hostapd/hostapd.conf
+++ b/contrib/wpa/hostapd/hostapd.conf
@@ -41,7 +41,6 @@ interface=wlan0
# bit 2 (4) = RADIUS
# bit 3 (8) = WPA
# bit 4 (16) = driver interface
-# bit 5 (32) = IAPP
# bit 6 (64) = MLME
#
# Levels (minimum value for logged events):
@@ -73,7 +72,7 @@ ctrl_interface=/var/run/hostapd
# run as non-root users. However, since the control interface can be used to
# change the network configuration, this access needs to be protected in many
# cases. By default, hostapd is configured to use gid 0 (root). If you
-# want to allow non-root users to use the contron interface, add a new group
+# want to allow non-root users to use the control interface, add a new group
# and change this value to match with that group. Add users that should have
# control interface access to this group.
#
@@ -147,7 +146,8 @@ ssid=test
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
+# to be set to hw_mode=a. When using ACS (see channel parameter), a
# special value "any" can be used to indicate that any support band can be used.
# This special case is currently supported only with drivers with which
# offloaded ACS is used.
@@ -164,8 +164,14 @@ hw_mode=g
# which will enable the ACS survey based algorithm.
channel=1
+# Global operating class (IEEE 802.11, Annex E, Table E-4)
+# This option allows hostapd to specify the operating class of the channel
+# configured with the channel parameter. channel and op_class together can
+# uniquely identify channels across different bands, including the 6 GHz band.
+#op_class=131
+
# ACS tuning - Automatic Channel Selection
-# See: http://wireless.kernel.org/en/users/Documentation/acs
+# See: https://wireless.wiki.kernel.org/en/users/documentation/acs
#
# You can customize the ACS survey algorithm with following variables:
#
@@ -199,11 +205,26 @@ channel=1
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
+# Frequency list restriction. This option allows hostapd to select one of the
+# provided frequencies when a frequency should be automatically selected.
+# Frequency list can be provided as range using hyphen ('-') or individual
+# frequencies can be specified by comma (',') separated values
+# Default: all frequencies allowed in selected hw_mode
+#freqlist=2437,5955,5975
+#freqlist=2437,5985-6105
+
# Exclude DFS channels from ACS
# This option can be used to exclude all DFS channels from the ACS channel list
# in cases where the driver supports DFS channels.
#acs_exclude_dfs=1
+# Include only preferred scan channels from 6 GHz band for ACS
+# This option can be used to include only preferred scan channels in the 6 GHz
+# band. This can be useful in particular for devices that operate only a 6 GHz
+# BSS without a collocated 2.4/5 GHz BSS.
+# Default behavior is to include all PSC and non-PSC channels.
+#acs_exclude_6ghz_non_psc=1
+
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -258,6 +279,8 @@ fragm_threshold=-1
# beacon_rate=ht:<HT MCS>
# VHT:
# beacon_rate=vht:<VHT MCS>
+# HE:
+# beacon_rate=he:<HE MCS>
#
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
#beacon_rate=10
@@ -550,6 +573,10 @@ wmm_ac_vo_acm=0
# Default: 1 (enabled)
#broadcast_deauth=1
+# Get notifications for received Management frames on control interface
+# Default: 0 (disabled)
+#notify_mgmt_frames=0
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -559,6 +586,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
#ieee80211n=1
+# disable_11n: Boolean (0/1) to disable HT for a specific BSS
+#disable_11n=0
+
# ht_capab: HT capabilities (list of flags)
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
@@ -577,8 +607,6 @@ wmm_ac_vo_acm=0
# channels if needed or creation of 40 MHz channel maybe rejected based
# on overlapping BSSes. These changes are done automatically when hostapd
# is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-# (SMPS disabled if neither is set)
# HT-greenfield: [GF] (disabled if not set)
# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
@@ -613,6 +641,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
+# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
+#disable_11ac=0
+
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@@ -767,6 +798,9 @@ wmm_ac_vo_acm=0
# 1 = enabled
#ieee80211ax=1
+# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
+#disable_11ax=0
+
#he_su_beamformer: HE single user beamformer support
# 0 = not supported (default)
# 1 = supported
@@ -785,6 +819,9 @@ wmm_ac_vo_acm=0
# he_bss_color: BSS color (1-63)
#he_bss_color=1
+# he_bss_color_partial: BSS color AID equation
+#he_bss_color_partial=0
+
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
#he_default_pe_duration=0
@@ -794,12 +831,27 @@ wmm_ac_vo_acm=0
# 1 = required
#he_twt_required=0
+#he_twt_responder: Whether TWT (HE) responder is enabled
+# 0 = disabled
+# 1 = enabled if supported by the driver (default)
+#he_twt_responder=1
+
#he_rts_threshold: Duration of STA transmission
# 0 = not set (default)
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
+# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80
+# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center
+# frequency of the lower frequency segment. he_oper_centr_freq_seg1_idx field
+# is used only with 80+80 MHz bandwidth operation and it is used to transmit
+# the center frequency of the second segment.
+# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
+# For example idx=3 would result in 5965 MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured operating class or center frequency indexes (see
+# IEEE P802.11ax/D6.1 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@@ -835,10 +887,82 @@ wmm_ac_vo_acm=0
#he_mu_edca_ac_vo_timer=255
# Spatial Reuse Parameter Set
+#
+# SR Control field value
+# B0 = PSR Disallowed
+# B1 = Non-SRG OBSS PD SR Disallowed
+# B2 = Non-SRG Offset Present
+# B3 = SRG Information Present
+# B4 = HESIGA_Spatial_reuse_value15_allowed
#he_spr_sr_control
+#
+# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1)
#he_spr_non_srg_obss_pd_max_offset
+
+# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1)
#he_spr_srg_obss_pd_min_offset
+#
+# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1)
#he_spr_srg_obss_pd_max_offset
+#
+# SPR SRG BSS Color (included if he_spr_sr_control B3=1)
+# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter
+# Set element that indicates the BSS color values used by members of the
+# SRG of which the transmitting STA is a member. The value is in range of 0-63.
+#he_spr_srg_bss_colors=1 2 10 63
+#
+# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1)
+# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse
+# Parameter Set element that indicates the Partial BSSID values used by members
+# of the SRG of which the transmitting STA is a member. The value range
+# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest
+# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit
+# corresponds to Partial BSSID value 63.
+#he_spr_srg_partial_bssid=0 1 3 63
+#
+#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities.
+# Indicates maximum MPDU length
+# 0 = 3895 octets
+# 1 = 7991 octets
+# 2 = 11454 octets (default)
+#he_6ghz_max_mpdu=2
+#
+#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band
+# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that
+# the STA can receive. This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+# 0 = AMPDU length of 8k
+# 1 = AMPDU length of 16k
+# 2 = AMPDU length of 32k
+# 3 = AMPDU length of 65k
+# 4 = AMPDU length of 131k
+# 5 = AMPDU length of 262k
+# 6 = AMPDU length of 524k
+# 7 = AMPDU length of 1048k (default)
+#he_6ghz_max_ampdu_len_exp=7
+#
+#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_rx_ant_pat=1
+#
+#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_tx_ant_pat=1
+
+# Unsolicited broadcast Probe Response transmission settings
+# This is for the 6 GHz band only. If the interval is set to a non-zero value,
+# the AP schedules unsolicited broadcast Probe Response frames to be
+# transmitted for in-band discovery. Refer to
+# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning.
+# Valid range: 0..20 TUs; default is 0 (disabled)
+#unsol_bcast_probe_resp_interval=0
##### IEEE 802.1X-2004 related configuration ##################################
@@ -877,6 +1001,8 @@ eapol_key_index_workaround=0
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
# reauthentication).
+# Note: Reauthentications may enforce a disconnection, check the related
+# parameter wpa_deny_ptk0_rekey for details.
#eap_reauth_period=3600
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
@@ -1012,7 +1138,7 @@ eap_server=0
#check_crl=1
# Specify whether to ignore certificate CRL validity time mismatches with
-# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
#
# 0 = ignore errors
# 1 = do not ignore errors (default)
@@ -1081,6 +1207,12 @@ eap_server=0
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
#tls_flags=[flag1][flag2]...
+# Maximum number of EAP message rounds with data (default: 100)
+#max_auth_rounds=100
+
+# Maximum number of short EAP message rounds (default: 50)
+#max_auth_rounds_short=50
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -1167,7 +1299,7 @@ eap_server=0
# should be unique across all issuing servers. In theory, this is a variable
# length field, but due to some existing implementations requiring A-ID to be
# 16 octets in length, it is strongly recommended to use that length for the
-# field to provid interoperability with deployed peer implementations. This
+# field to provide interoperability with deployed peer implementations. This
# field is configured in hex format.
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
@@ -1194,6 +1326,8 @@ eap_server=0
# EAP-TEAP authentication type
# 0 = inner EAP (default)
# 1 = Basic-Password-Auth
+# 2 = Do not require Phase 2 authentication if client can be authenticated
+# during Phase 1
#eap_teap_auth=0
# EAP-TEAP authentication behavior when using PAC
@@ -1201,6 +1335,20 @@ eap_server=0
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
#eap_teap_pac_no_inner=0
+# EAP-TEAP behavior with Result TLV
+# 0 = include with Intermediate-Result TLV (default)
+# 1 = send in a separate message (for testing purposes)
+#eap_teap_separate_result=0
+
+# EAP-TEAP identities
+# 0 = allow any identity type (default)
+# 1 = require user identity
+# 2 = require machine identity
+# 3 = request user identity; accept either user or machine identity
+# 4 = request machine identity; accept either user or machine identity
+# 5 = require both user and machine identity
+#eap_teap_id=0
+
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
@@ -1223,11 +1371,6 @@ eap_server=0
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
-##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
-
-# Interface to be used for IAPP broadcast packets
-#iapp_interface=eth0
-
##### RADIUS client configuration #############################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
@@ -1261,6 +1404,12 @@ own_ip_addr=127.0.0.1
# used, e.g., when the device has multiple IP addresses.
#radius_client_addr=127.0.0.1
+# RADIUS client forced local interface. Helps run properly with VRF
+# Default is none set which allows the network stack to pick the appropriate
+# interface automatically.
+# Example below binds to eth0
+#radius_client_dev=eth0
+
# RADIUS authentication server
#auth_server_addr=127.0.0.1
#auth_server_port=1812
@@ -1466,6 +1615,17 @@ own_ip_addr=127.0.0.1
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
#wpa=2
+# Extended Key ID support for Individually Addressed frames
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#extended_key_id=0
+
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
@@ -1566,8 +1726,26 @@ own_ip_addr=127.0.0.1
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and with such
+# devices, the only secure method to rekey the PTK without Extended Key ID
+# support requires a disconnection. Check the related parameter
+# wpa_deny_ptk0_rekey for details.
#wpa_ptk_rekey=600
+# Workaround for PTK rekey issues
+#
+# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
+# Addressed Frames") can degrade the security and stability with some cards.
+# To avoid such issues hostapd can replace those PTK rekeys (including EAP
+# reauthentications) with disconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow PTK0 rekeys
+#wpa_deny_ptk0_rekey=0
+
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
# Handshake are retried per 4-Way Handshake attempt.
# (dot11RSNAConfigPairwiseUpdateCount)
@@ -1618,6 +1796,12 @@ own_ip_addr=127.0.0.1
# 1 = optional
# 2 = required
#ieee80211w=0
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE
# Group management cipher suite
# Default: AES-128-CMAC (BIP)
@@ -1630,6 +1814,13 @@ own_ip_addr=127.0.0.1
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
+# Beacon Protection (management frame protection for Beacon frames)
+# This depends on management frame protection being enabled (ieee80211w != 0)
+# and beacon protection support indication from the driver.
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -1642,9 +1833,25 @@ own_ip_addr=127.0.0.1
# ocv: Operating Channel Validation
# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this depends on the driver's support for OCV when the driver SME is
+# used. If hostapd SME is used, this will be enabled just based on this
+# configuration.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled
+# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
+# connect even if the STA doesn't send OCI or negotiate PMF. This
+# workaround is to improve interoperability with legacy STAs which are
+# wrongly copying reserved bits of RSN capabilities from the AP's
+# RSNE into (Re)Association Request frames. When this configuration is
+# enabled, the AP considers STA is OCV capable only when the STA indicates
+# MFP capability in (Re)Association Request frames and sends OCI in
+# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
+# Request frame; otherwise, the AP disables OCV for the current connection
+# with the STA. Enabling this workaround mode reduced OCV protection to
+# some extend since it allows misbehavior to go through. As such, this
+# should be enabled only if interoperability with misbehaving STAs is
+# needed.
#ocv=1
# disable_pmksa_caching: Disable PMKSA caching
@@ -1676,7 +1883,7 @@ own_ip_addr=127.0.0.1
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
# addition, an optional VLAN ID specification can be used to bind the station
-# to the specified VLAN whenver the specific SAE password entry is used.
+# to the specified VLAN whenever the specific SAE password entry is used.
#
# If the peer MAC address is not included or is set to the wildcard address
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
@@ -1691,7 +1898,8 @@ own_ip_addr=127.0.0.1
# special meaning of removing all previously added entries.
#
# sae_password uses the following encoding:
-#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
+#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
# Examples:
#sae_password=secret
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
@@ -1701,10 +1909,11 @@ own_ip_addr=127.0.0.1
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
-#sae_anti_clogging_threshold=5
+#sae_anti_clogging_threshold=5 (deprecated)
+#anti_clogging_threshold=5
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
-# The offending SAe peer will be disconnected if more than this many
+# The offending SAE peer will be disconnected if more than this many
# synchronization errors happen.
#sae_sync=5
@@ -1729,6 +1938,23 @@ own_ip_addr=127.0.0.1
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
#sae_require_mfp=0
+# SAE Confirm behavior
+# By default, AP will send out only SAE Commit message in response to a received
+# SAE Commit message. This parameter can be set to 1 to override that behavior
+# to send both SAE Commit and SAE Confirm messages without waiting for the STA
+# to send its SAE Confirm message first.
+#sae_confirm_immediate=0
+
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
+#sae_pwe=0
+
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@@ -1753,6 +1979,19 @@ own_ip_addr=127.0.0.1
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
#owe_groups=19 20 21
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
# OWE transition mode configuration
# Pointer to the matching open/OWE BSS
#owe_transition_bssid=<bssid>
@@ -1790,6 +2029,45 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
+# FILS Discovery frame transmission minimum and maximum interval settings.
+# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
+# frame transmission. These values use TUs as the unit and have allowed range
+# of 0-10000. fils_discovery_min_interval defaults to 20.
+#fils_discovery_min_interval=20
+#fils_discovery_max_interval=0
+
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode in their
+# network profiles when the network has completed transition steps, i.e., once
+# sufficiently large number of APs in the ESS have been updated to support the
+# more secure alternative. When this indication is used, the stations are
+# expected to automatically disable transition mode and less secure security
+# options. This includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
+# allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
+# (default: 0 = do not include Transition Disable KDE)
+#transition_disable=0x01
+
+# PASN ECDH groups
+# PASN implementations are required to support group 19 (NIST P-256). If this
+# parameter is not set, only group 19 is supported by default. This
+# configuration parameter can be used to specify a limited set of allowed
+# groups. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#pasn_groups=19 20 21
+
+# PASN comeback after time in TUs
+# In case the AP is temporarily unable to handle a PASN authentication exchange
+# due to a too large number of parallel operations, this value indicates to the
+# peer after how many TUs it can try the PASN exchange again.
+# (default: 10 TUs)
+#pasn_comeback_after=10
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -1833,7 +2111,7 @@ own_ip_addr=127.0.0.1
# Wildcard entry:
# Upon receiving a response from R0KH, it will be added to this list, so
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
-# blacklisted.
+# temporarily blocked (see rkh_neg_timeout).
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
@@ -1889,7 +2167,7 @@ own_ip_addr=127.0.0.1
#ft_psk_generate_local=0
##### Neighbor table ##########################################################
-# Maximum number of entries kept in AP table (either for neigbor table or for
+# Maximum number of entries kept in AP table (either for neighbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
# removed when adding a new entry that would make the list grow over this
# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
@@ -2143,6 +2421,13 @@ own_ip_addr=127.0.0.1
#wps_nfc_dh_privkey: Hexdump of DH Private Key
#wps_nfc_dev_pw: Hexdump of Device Password
+# Application Extension attribute for Beacon and Probe Response frames
+# This parameter can be used to add application extension into WPS IE. The
+# contents of this parameter starts with 16-octet (32 hexdump characters) of
+# UUID to identify the specific application and that is followed by the actual
+# application specific data.
+#wps_application_ext=<hexdump>
+
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@@ -2151,6 +2436,31 @@ own_ip_addr=127.0.0.1
# Allow cross connection
#allow_cross_connection=1
+##### Device Provisioning Protocol (DPP) ######################################
+
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
+#dpp_connector
+#dpp_netaccesskey
+#dpp_netaccesskey_expiry
+#dpp_csign
+#dpp_controller
+
+# Configurator Connectivity indication
+# 0: no Configurator is currently connected (default)
+# 1: advertise that a Configurator is available
+#dpp_configurator_connectivity=0
+
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@@ -2531,7 +2841,7 @@ own_ip_addr=127.0.0.1
# Default is 0 = OCE disabled
#oce=0
-# RSSI-based assocition rejection
+# RSSI-based association rejection
#
# Reject STA association if RSSI is below given threshold (in dBm)
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
@@ -2546,6 +2856,10 @@ own_ip_addr=127.0.0.1
# threshold (range: 0..255, default=30).
#rssi_reject_assoc_timeout=30
+# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+#rssi_ignore_probe_request=-75
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
@@ -2638,6 +2952,19 @@ own_ip_addr=127.0.0.1
# airtime.
#airtime_bss_limit=1
+##### EDMG support ############################################################
+#
+# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
+# To configure channel bonding for an EDMG AP use edmg_channel below.
+# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
+# configured.
+#enable_edmg=1
+#
+# Configure channel bonding for AP mode in the 60 GHz band.
+# This parameter is relevant only if enable_edmg is set.
+# Default value is 0 (no channel bonding).
+#edmg_channel=9
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/contrib/wpa/hostapd/hostapd.wpa_psk b/contrib/wpa/hostapd/hostapd.wpa_psk
index 166e59e9c64f..2ce5ff2346df 100644
--- a/contrib/wpa/hostapd/hostapd.wpa_psk
+++ b/contrib/wpa/hostapd/hostapd.wpa_psk
@@ -7,9 +7,15 @@
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
+# An optional WPS tag can be added by prefixing the line with
+# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
+# generating a PSK for a WPS Enrollee instead of generating a new random
+# per-Enrollee PSK.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
+wps=1 00:00:00:00:00:00 passphrase for WPS
+wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c
index 046024390f84..eaa628ad0676 100644
--- a/contrib/wpa/hostapd/hostapd_cli.c
+++ b/contrib/wpa/hostapd/hostapd_cli.c
@@ -54,7 +54,7 @@ static void usage(void)
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
- "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
+ "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] "
"[-a<path>] \\\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
@@ -68,6 +68,9 @@ static void usage(void)
" -a<file> run in daemon mode executing the action file "
"based on events\n"
" from hostapd\n"
+ " -r try to reconnect when client socket is "
+ "disconnected.\n"
+ " This is useful only when used with -a.\n"
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
@@ -401,7 +404,6 @@ static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -414,7 +416,6 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -974,7 +975,7 @@ static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
dir = opendir(ctrl_iface_dir);
if (dir == NULL) {
printf("Control interface directory '%s' could not be "
- "openned.\n", ctrl_iface_dir);
+ "opened.\n", ctrl_iface_dir);
return;
}
@@ -1226,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
char cmd[256];
int res;
- if (argc < 2 || argc > 3) {
+ if (argc < 2 || argc > 4) {
printf("Invalid vendor command\n"
- "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
+ "usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
- argc == 3 ? argv[2] : "");
+ res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
+ argv[1], argc >= 3 ? argv[2] : "",
+ argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n");
return -1;
@@ -1311,24 +1313,17 @@ static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
}
-static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[400];
- int res;
+ return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR");
+}
- if (argc != 2) {
- printf("Invalid remove_neighbor command: needs 2 arguments\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
- argv[0], argv[1]);
- if (os_snprintf_error(sizeof(cmd), res)) {
- printf("Too long REMOVE_NEIGHBOR command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv);
}
@@ -1408,6 +1403,13 @@ static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1470,6 +1472,37 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
+}
+
+
+static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -1508,6 +1541,14 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
}
+#ifdef ANDROID
+static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
+}
+#endif /* ANDROID */
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1542,10 +1583,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
"<addr> = get taxonomy signature for a station" },
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
"<addr> = send SA Query to a station" },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
@@ -1637,8 +1676,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
"<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
" = add AP to neighbor database" },
+ { "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL,
+ " = show neighbor database entries" },
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
- "<addr> <ssid=> = remove AP from neighbor database" },
+ "<addr> [ssid=<hex>] = remove AP from neighbor database" },
{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
"<addr> = send LCI request to a station"},
{ "req_range", hostapd_cli_cmd_req_range, NULL,
@@ -1656,6 +1697,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<id> = get DPP bootstrap URI" },
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
@@ -1676,6 +1719,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
+ "[tcp_port=<port>] [role=..] = start DPP controller" },
+ { "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
+ "= stop DPP controller" },
+ { "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },
@@ -1687,6 +1740,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
"= reload wpa_psk_file only" },
+#ifdef ANDROID
+ { "driver", hostapd_cli_cmd_driver, NULL,
+ "<driver sub command> [<hex formatted data>] = send driver command data" },
+#endif /* ANDROID */
{ NULL, NULL, NULL, NULL }
};
@@ -2011,12 +2068,13 @@ int main(int argc, char *argv[])
int warning_displayed = 0;
int c;
int daemonize = 0;
+ int reconnect = 0;
if (os_program_init())
return -1;
for (;;) {
- c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
+ c = getopt(argc, argv, "a:BhG:i:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -2045,6 +2103,9 @@ int main(int argc, char *argv[])
case 'P':
pid_file = optarg;
break;
+ case 'r':
+ reconnect = 1;
+ break;
case 's':
client_socket_dir = optarg;
break;
@@ -2087,8 +2148,7 @@ int main(int argc, char *argv[])
printf("Connection established.\n");
break;
}
-
- if (!interactive) {
+ if (!interactive && !reconnect) {
perror("Failed to connect to hostapd - "
"wpa_ctrl_open");
return -1;
@@ -2106,8 +2166,14 @@ int main(int argc, char *argv[])
return -1;
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
-
- if (interactive)
+ if (reconnect && action_file && ctrl_ifname) {
+ while (!hostapd_cli_quit) {
+ if (ctrl_conn)
+ hostapd_cli_action(ctrl_conn);
+ os_sleep(1, 0);
+ hostapd_cli_reconnect(ctrl_ifname);
+ }
+ } else if (interactive)
hostapd_cli_interactive();
else if (action_file)
hostapd_cli_action(ctrl_conn);
diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c
index 08896ffe2a79..4f2d1f21659e 100644
--- a/contrib/wpa/hostapd/main.c
+++ b/contrib/wpa/hostapd/main.c
@@ -81,9 +81,6 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
- case HOSTAPD_MODULE_IAPP:
- module_str = "IAPP";
- break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
@@ -221,7 +218,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
- iface->smps_modes = capa.smps_modes;
+ iface->drv_flags2 = capa.flags2;
iface->probe_resp_offloads = capa.probe_resp_offloads;
/*
* Use default extended capa values from per-radio information
@@ -263,7 +260,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
struct hostapd_iface *iface;
int k;
- wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+ wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
@@ -454,11 +451,12 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
static void show_version(void)
{
fprintf(stderr,
- "hostapd v" VERSION_STR "\n"
+ "hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
- "and contributors\n");
+ "and contributors\n",
+ VERSION_STR);
}
@@ -676,7 +674,10 @@ int main(int argc, char *argv[])
#endif /* CONFIG_ETH_P_OUI */
#ifdef CONFIG_DPP
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
- /* TODO: dpp_conf.msg_ctx? */
+ dpp_conf.cb_ctx = &interfaces;
+#ifdef CONFIG_DPP2
+ dpp_conf.remove_bi = hostapd_dpp_remove_bi;
+#endif /* CONFIG_DPP2 */
interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp)
return -1;
@@ -771,7 +772,7 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_open_file(log_file);
- else
+ if (!log_file && !wpa_debug_syslog)
wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog)
@@ -905,8 +906,11 @@ int main(int argc, char *argv[])
!!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]);
+ interfaces.iface[i] = NULL;
}
os_free(interfaces.iface);
+ interfaces.iface = NULL;
+ interfaces.count = 0;
#ifdef CONFIG_DPP
dpp_global_deinit(interfaces.dpp);
diff --git a/contrib/wpa/hostapd/sae_pk_gen.c b/contrib/wpa/hostapd/sae_pk_gen.c
new file mode 100644
index 000000000000..c31eff75b538
--- /dev/null
+++ b/contrib/wpa/hostapd/sae_pk_gen.c
@@ -0,0 +1,196 @@
+/*
+ * SAE-PK password/modifier generator
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
+#include "common/sae.h"
+
+
+int main(int argc, char *argv[])
+{
+ char *der = NULL;
+ size_t der_len;
+ struct crypto_ec_key *key = NULL;
+ struct wpabuf *pub = NULL;
+ u8 *data = NULL, *m;
+ size_t data_len;
+ char *b64 = NULL, *pw = NULL, *pos, *src;
+ int sec, j;
+ int ret = -1;
+ u8 hash[SAE_MAX_HASH_LEN];
+ char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
+ u8 pw_base_bin[SAE_MAX_HASH_LEN];
+ u8 *dst;
+ int group;
+ size_t hash_len;
+ unsigned long long i, expected;
+ char m_hex[2 * SAE_PK_M_LEN + 1];
+ u32 sec_1b, val20;
+
+ wpa_debug_level = MSG_INFO;
+ if (os_program_init() < 0)
+ goto fail;
+
+ if (argc != 4) {
+ fprintf(stderr,
+ "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
+ goto fail;
+ }
+
+ sec = atoi(argv[2]);
+ if (sec != 3 && sec != 5) {
+ fprintf(stderr,
+ "Invalid Sec value (allowed values: 3 and 5)\n");
+ goto fail;
+ }
+ sec_1b = sec == 3;
+ expected = 1;
+ for (j = 0; j < sec; j++)
+ expected *= 256;
+
+ der = os_readfile(argv[1], &der_len);
+ if (!der) {
+ fprintf(stderr, "Could not read %s: %s\n",
+ argv[1], strerror(errno));
+ goto fail;
+ }
+
+ key = crypto_ec_key_parse_priv((u8 *) der, der_len);
+ if (!key) {
+ fprintf(stderr, "Could not parse ECPrivateKey\n");
+ goto fail;
+ }
+
+ pub = crypto_ec_key_get_subject_public_key(key);
+ if (!pub) {
+ fprintf(stderr, "Failed to build SubjectPublicKey\n");
+ goto fail;
+ }
+
+ group = crypto_ec_key_group(key);
+ switch (group) {
+ case 19:
+ hash_len = 32;
+ break;
+ case 20:
+ hash_len = 48;
+ break;
+ case 21:
+ hash_len = 64;
+ break;
+ default:
+ fprintf(stderr, "Unsupported private key group\n");
+ goto fail;
+ }
+
+ data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
+ data = os_malloc(data_len);
+ if (!data) {
+ fprintf(stderr, "No memory for data buffer\n");
+ goto fail;
+ }
+ os_memcpy(data, argv[3], os_strlen(argv[3]));
+ m = data + os_strlen(argv[3]);
+ if (os_get_random(m, SAE_PK_M_LEN) < 0) {
+ fprintf(stderr, "Could not generate random Modifier M\n");
+ goto fail;
+ }
+ os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
+
+ fprintf(stderr, "Searching for a suitable Modifier M value\n");
+ for (i = 0;; i++) {
+ if (sae_hash(hash_len, data, data_len, hash) < 0) {
+ fprintf(stderr, "Hash failed\n");
+ goto fail;
+ }
+ if (hash[0] == 0 && hash[1] == 0) {
+ if ((hash[2] & 0xf0) == 0)
+ fprintf(stderr, "\r%3.2f%%",
+ 100.0 * (double) i / (double) expected);
+ for (j = 2; j < sec; j++) {
+ if (hash[j])
+ break;
+ }
+ if (j == sec)
+ break;
+ }
+ inc_byte_array(m, SAE_PK_M_LEN);
+ }
+
+ if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
+ wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
+ goto fail;
+ fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
+ i + 1, hash_hex);
+
+ b64 = base64_encode(der, der_len, NULL);
+ if (!b64)
+ goto fail;
+ src = pos = b64;
+ while (*src) {
+ if (*src != '\n')
+ *pos++ = *src;
+ src++;
+ }
+ *pos = '\0';
+
+ /* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
+ * one. */
+ os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
+ dst = pw_base_bin;
+ for (j = 0; j < 8 * (int) hash_len / 20; j++) {
+ val20 = sae_pk_get_be19(hash + sec);
+ val20 |= sec_1b << 19;
+ sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
+
+ if (j & 1) {
+ *dst |= (val20 >> 16) & 0x0f;
+ dst++;
+ *dst++ = (val20 >> 8) & 0xff;
+ *dst++ = val20 & 0xff;
+ } else {
+ *dst++ = (val20 >> 12) & 0xff;
+ *dst++ = (val20 >> 4) & 0xff;
+ *dst = (val20 << 4) & 0xf0;
+ }
+ }
+ if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
+ pw_base_bin, hash_len - sec) >= 0)
+ fprintf(stderr, "PasswordBase binary data for base32: %s",
+ hash_hex);
+
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
+ if (!pw)
+ goto fail;
+
+ printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
+ printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
+ printf("# Longer passwords can be used for improved security at the cost of usability:\n");
+ for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
+ os_free(pw);
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
+ if (pw)
+ printf("# %s\n", pw);
+ }
+
+ ret = 0;
+fail:
+ os_free(der);
+ wpabuf_free(pub);
+ crypto_ec_key_deinit(key);
+ os_free(data);
+ os_free(b64);
+ os_free(pw);
+
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/contrib/wpa/hs20/client/Makefile b/contrib/wpa/hs20/client/Makefile
index 67f6f55c5260..4dcfe2d3bf2c 100644
--- a/contrib/wpa/hs20/client/Makefile
+++ b/contrib/wpa/hs20/client/Makefile
@@ -1,28 +1,6 @@
-all: hs20-osu-client
+ALL=hs20-osu-client
-ifndef CC
-CC=gcc
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-else
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../../src/build.rules
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common
@@ -30,8 +8,17 @@ CFLAGS += -I../../src
ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM
+TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
+ifeq ($(TEST_WK),)
+# Try webkit2
+GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
+GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
+CFLAGS += -DUSE_WEBKIT2
+else
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
+endif
+
CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS)
endif
@@ -84,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-
-clean:
- rm -f core *~ *.o *.d hs20-osu-client
- rm -f ../../src/utils/*.o
- rm -f ../../src/utils/*.d
- rm -f ../../src/common/*.o
- rm -f ../../src/common/*.d
- rm -f ../../src/crypto/*.o
- rm -f ../../src/crypto/*.d
- rm -f ../../src/wps/*.o
- rm -f ../../src/wps/*.d
-
--include $(OBJS:%.o=%.d)
+clean: common-clean
+ rm -f core *~
diff --git a/contrib/wpa/hs20/client/est.c b/contrib/wpa/hs20/client/est.c
index db65334b20f3..97f9132100c4 100644
--- a/contrib/wpa/hs20/client/est.c
+++ b/contrib/wpa/hs20/client/est.c
@@ -158,7 +158,7 @@ int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
return -1;
}
- pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
+ pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 && pkcs7_len < resp_len / 2) {
wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
(unsigned int) pkcs7_len, (unsigned int) resp_len);
@@ -639,8 +639,7 @@ int est_build_csr(struct hs20_osu_client *ctx, const char *url)
return -1;
}
- attrs = base64_decode((unsigned char *) resp, resp_len,
- &attrs_len);
+ attrs = base64_decode(resp, resp_len, &attrs_len);
os_free(resp);
if (attrs == NULL) {
@@ -734,7 +733,7 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
- pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
+ pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
pkcs7 = os_malloc(resp_len);
diff --git a/contrib/wpa/hs20/client/oma_dm_client.c b/contrib/wpa/hs20/client/oma_dm_client.c
index d75c84562aca..bcd68b8775d5 100644
--- a/contrib/wpa/hs20/client/oma_dm_client.c
+++ b/contrib/wpa/hs20/client/oma_dm_client.c
@@ -407,7 +407,7 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
wpa_printf(MSG_INFO, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "Launch browser to URI '%s'", data);
- res = hs20_web_browser(data);
+ res = hs20_web_browser(data, 1);
xml_node_get_text_free(ctx->xml, data);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully");
diff --git a/contrib/wpa/hs20/client/osu_client.c b/contrib/wpa/hs20/client/osu_client.c
index fd99600da788..11bf0db35e93 100644
--- a/contrib/wpa/hs20/client/osu_client.c
+++ b/contrib/wpa/hs20/client/osu_client.c
@@ -310,7 +310,7 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
size_t len;
u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
int res;
- unsigned char *b64;
+ char *b64;
FILE *f;
url_node = get_node(ctx->xml, params, "CertURL");
@@ -364,7 +364,7 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
return -1;
}
- b64 = base64_encode((unsigned char *) cert, len, NULL);
+ b64 = base64_encode(cert, len, NULL);
os_free(cert);
if (b64 == NULL)
return -1;
@@ -2233,7 +2233,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
wpa_ctrl_close(mon);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not connect");
+ wpa_printf(MSG_INFO, "Could not connect to OSU network");
write_summary(ctx, "Could not connect to OSU network");
wpa_printf(MSG_INFO, "Remove OSU network connection");
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
@@ -2406,7 +2406,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
write_summary(ctx, "Start web browser with OSU provider selection page");
- ret = hs20_web_browser(fname);
+ ret = hs20_web_browser(fname, 0);
selected:
if (ret > 0 && (size_t) ret <= osu_count) {
@@ -2907,7 +2907,7 @@ static char * get_hostname(const char *url)
static int osu_cert_cb(void *_ctx, struct http_cert *cert)
{
struct hs20_osu_client *ctx = _ctx;
- unsigned int i, j;
+ size_t i, j;
int found;
char *host = NULL;
@@ -3002,7 +3002,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO,
- "[%i] Looking for icon file name '%s' match",
+ "[%zu] Looking for icon file name '%s' match",
j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
@@ -3010,7 +3010,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
char *pos;
wpa_printf(MSG_INFO,
- "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+ "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short");
@@ -3044,7 +3044,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
if (logo->hash_len != 32) {
wpa_printf(MSG_INFO,
- "[%i][%i] Icon hash length invalid (should be 32): %d",
+ "[%zu][%zu] Icon hash length invalid (should be 32): %d",
j, i, (int) logo->hash_len);
continue;
}
@@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
}
wpa_printf(MSG_DEBUG,
- "[%u][%u] Icon hash did not match", j, i);
+ "[%zu][%zu] Icon hash did not match", j, i);
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
@@ -3152,7 +3152,7 @@ static void check_workarounds(struct hs20_osu_client *ctx)
static void usage(void)
{
- printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
+ printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
@@ -3198,7 +3198,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
+ c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
if (c < 0)
break;
switch (c) {
@@ -3236,6 +3236,9 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
+ case 'T':
+ ctx.ignore_tls = 1;
+ break;
case 'w':
wpas_ctrl_path = optarg;
break;
@@ -3403,7 +3406,7 @@ int main(int argc, char *argv[])
wpa_printf(MSG_INFO, "Launch web browser to URL %s",
argv[optind + 1]);
- ret = hs20_web_browser(argv[optind + 1]);
+ ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
} else if (strcmp(argv[optind], "parse_cert") == 0) {
if (argc - optind < 2) {
diff --git a/contrib/wpa/hs20/client/osu_client.h b/contrib/wpa/hs20/client/osu_client.h
index 5c8e6d00b6bb..9b45b03febe2 100644
--- a/contrib/wpa/hs20/client/osu_client.h
+++ b/contrib/wpa/hs20/client/osu_client.h
@@ -50,6 +50,8 @@ struct hs20_osu_client {
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
+ int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
+ * server certificate */
};
diff --git a/contrib/wpa/hs20/client/spp_client.c b/contrib/wpa/hs20/client/spp_client.c
index c619541ae286..39d10e0362f6 100644
--- a/contrib/wpa/hs20/client/spp_client.c
+++ b/contrib/wpa/hs20/client/spp_client.c
@@ -547,7 +547,7 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
}
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "Launch browser to URI '%s'", uri);
- res = hs20_web_browser(uri);
+ res = hs20_web_browser(uri, 1);
xml_node_get_text_free(ctx->xml, uri);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
diff --git a/contrib/wpa/hs20/server/Makefile b/contrib/wpa/hs20/server/Makefile
new file mode 100644
index 000000000000..0cab6d6b010a
--- /dev/null
+++ b/contrib/wpa/hs20/server/Makefile
@@ -0,0 +1,42 @@
+ALL=hs20_spp_server
+
+include ../../src/build.rules
+
+CFLAGS += -I../../src
+CFLAGS += -I../../src/utils
+CFLAGS += -I../../src/crypto
+
+LIBS += -lsqlite3
+
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../../.git),../../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
+OBJS=spp_server.o
+OBJS += hs20_spp_server.o
+OBJS += ../../src/utils/xml-utils.o
+OBJS += ../../src/utils/base64.o
+OBJS += ../../src/utils/common.o
+OBJS += ../../src/utils/os_unix.o
+OBJS += ../../src/utils/wpa_debug.o
+OBJS += ../../src/crypto/md5-internal.o
+CFLAGS += $(shell xml2-config --cflags)
+LIBS += $(shell xml2-config --libs)
+OBJS += ../../src/utils/xml_libxml2.o
+
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
+hs20_spp_server: $(OBJS)
+ $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
+
+clean: common-clean
+ rm -f core *~
diff --git a/contrib/wpa/hs20/server/ca/clean.sh b/contrib/wpa/hs20/server/ca/clean.sh
new file mode 100755
index 000000000000..c72dcbda45e9
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/clean.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+for i in server-client server server-revoked user ocsp; do
+ rm -f $i.csr $i.key $i.pem
+done
+
+rm -f openssl.cnf.tmp
+if [ -d demoCA ]; then
+ rm -r demoCA
+fi
+rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
+rm -f my-openssl.cnf my-openssl-root.cnf
+#rm -r rootCA
diff --git a/contrib/wpa/hs20/server/ca/est-csrattrs.cnf b/contrib/wpa/hs20/server/ca/est-csrattrs.cnf
new file mode 100644
index 000000000000..b50ea00d0b77
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/est-csrattrs.cnf
@@ -0,0 +1,17 @@
+asn1 = SEQUENCE:attrs
+
+[attrs]
+#oid1 = OID:challengePassword
+attr1 = SEQUENCE:extreq
+oid2 = OID:sha256WithRSAEncryption
+
+[extreq]
+oid = OID:extensionRequest
+vals = SET:extreqvals
+
+[extreqvals]
+
+oid1 = OID:macAddress
+#oid2 = OID:imei
+#oid3 = OID:meid
+#oid4 = OID:DevId
diff --git a/contrib/wpa/hs20/server/ca/est-csrattrs.sh b/contrib/wpa/hs20/server/ca/est-csrattrs.sh
new file mode 100755
index 000000000000..0b73a0408284
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/est-csrattrs.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid
+base64 est-csrattrs.der > est-attrs.b64
diff --git a/contrib/wpa/hs20/server/ca/hs20.oid b/contrib/wpa/hs20/server/ca/hs20.oid
new file mode 100644
index 000000000000..a829ff29bf44
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/hs20.oid
@@ -0,0 +1,7 @@
+1.3.6.1.1.1.1.22 macAddress
+1.2.840.113549.1.9.14 extensionRequest
+1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName
+1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth
+1.3.6.1.4.1.40808.1.1.3 imei
+1.3.6.1.4.1.40808.1.1.4 meid
+1.3.6.1.4.1.40808.1.1.5 DevId
diff --git a/contrib/wpa/hs20/server/ca/ocsp-req.sh b/contrib/wpa/hs20/server/ca/ocsp-req.sh
new file mode 100755
index 000000000000..931a20696d02
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/ocsp-req.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+for i in *.pem; do
+ echo "===[ $i ]==================="
+ openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
+
+# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
+
+# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
+# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
+done
diff --git a/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh b/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh
new file mode 100755
index 000000000000..116c6e1c3d01
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA demoCA/cacert.pem -resp_no_certs -text
diff --git a/contrib/wpa/hs20/server/ca/ocsp-responder.sh b/contrib/wpa/hs20/server/ca/ocsp-responder.sh
new file mode 100755
index 000000000000..620947d01af0
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/ocsp-responder.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
diff --git a/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh b/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh
new file mode 100755
index 000000000000..f2b23250cadd
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
+openssl ocsp \
+ -no_nonce \
+ -CAfile ca.pem \
+ -verify_other demoCA/cacert.pem \
+ -issuer demoCA/cacert.pem \
+ -cert server.pem \
+ -url http://localhost:8888/ \
+ -respout ocsp-server-cache.der
diff --git a/contrib/wpa/hs20/server/ca/openssl-root.cnf b/contrib/wpa/hs20/server/ca/openssl-root.cnf
new file mode 100644
index 000000000000..5bc50be1dbc9
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/openssl-root.cnf
@@ -0,0 +1,125 @@
+# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA)
+
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+oid_section = new_oids
+
+[ new_oids ]
+
+#logotypeoid=1.3.6.1.5.5.7.1.12
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = ./rootCA # Where everything is kept
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+#unique_subject = no # Set to 'no' to allow creation of
+ # several certificates with same subject
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crlnumber = $dir/crlnumber # the current crl number
+ # must be commented out to leave a V1 CRL
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem# The private key
+RANDFILE = $dir/private/.rand # private random number file
+
+x509_extensions = usr_cert # The extentions to add to the cert
+
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+default_days = 365 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = default # use public key default MD
+preserve = no # keep passed DN ordering
+
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = optional
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+default_bits = 2048
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extentions to add to the self signed cert
+
+input_password = @PASSWORD@
+output_password = @PASSWORD@
+
+string_mask = utf8only
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+localityName = Locality Name (eg, city)
+localityName_default = Tuusula
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = WFA Hotspot 2.0
+
+##organizationalUnitName = Organizational Unit Name (eg, section)
+#organizationalUnitName_default =
+#@OU@
+
+commonName = Common Name (e.g. server FQDN or YOUR name)
+#@CN@
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_max = 64
+
+[ req_attributes ]
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+subjectAltName=DNS:example.com,DNS:another.example.com
+
+[ v3_ca ]
+
+# Hotspot 2.0 PKI requirements
+subjectKeyIdentifier=hash
+basicConstraints = critical,CA:true
+keyUsage = critical, cRLSign, keyCertSign
+
+[ crl_ext ]
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ v3_OCSP ]
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = OCSPSigning
diff --git a/contrib/wpa/hs20/server/ca/openssl.cnf b/contrib/wpa/hs20/server/ca/openssl.cnf
new file mode 100644
index 000000000000..61410138340f
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/openssl.cnf
@@ -0,0 +1,200 @@
+# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA)
+
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+oid_section = new_oids
+
+[ new_oids ]
+
+#logotypeoid=1.3.6.1.5.5.7.1.12
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = ./demoCA # Where everything is kept
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+#unique_subject = no # Set to 'no' to allow creation of
+ # several certificates with same subject
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crlnumber = $dir/crlnumber # the current crl number
+ # must be commented out to leave a V1 CRL
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem# The private key
+RANDFILE = $dir/private/.rand # private random number file
+
+x509_extensions = ext_client # The extentions to add to the cert
+
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+
+# Extension copying option: use with caution.
+copy_extensions = copy
+
+default_days = 365 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = default # use public key default MD
+preserve = no # keep passed DN ordering
+
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = supplied
+stateOrProvinceName = optional
+organizationName = supplied
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_osu_server ]
+countryName = match
+stateOrProvinceName = optional
+organizationName = match
+organizationalUnitName = supplied
+commonName = supplied
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+default_bits = 2048
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extentions to add to the self signed cert
+
+input_password = @PASSWORD@
+output_password = @PASSWORD@
+
+string_mask = utf8only
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = FI
+countryName_min = 2
+countryName_max = 2
+
+localityName = Locality Name (eg, city)
+localityName_default = Tuusula
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = @DOMAIN@
+
+##organizationalUnitName = Organizational Unit Name (eg, section)
+#organizationalUnitName_default =
+#@OU@
+
+commonName = Common Name (e.g. server FQDN or YOUR name)
+#@CN@
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_max = 64
+
+[ req_attributes ]
+
+[ v3_ca ]
+
+# Hotspot 2.0 PKI requirements
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, cRLSign, keyCertSign
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
+# For SP intermediate CA
+#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
+#nameConstraints=permitted;DNS:.@DOMAIN@
+#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
+
+[ v3_osu_server ]
+
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, keyEncipherment
+#@ALTNAME@
+
+#logotypeoid=ASN1:SEQUENCE:LogotypeExtn
+1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
+[LogotypeExtn]
+communityLogos=EXP:0,SEQUENCE:LogotypeInfo
+[LogotypeInfo]
+# note: implicit tag converted to explicit for CHOICE
+direct=EXP:0,SEQUENCE:LogotypeData
+[LogotypeData]
+image=SEQUENCE:LogotypeImage
+[LogotypeImage]
+imageDetails=SEQUENCE:LogotypeDetails
+imageInfo=SEQUENCE:LogotypeImageInfo
+[LogotypeDetails]
+mediaType=IA5STRING:image/png
+logotypeHash=SEQUENCE:HashAlgAndValues
+logotypeURI=SEQUENCE:URI
+[HashAlgAndValues]
+value1=SEQUENCE:HashAlgAndValueSHA256
+#value2=SEQUENCE:HashAlgAndValueSHA1
+[HashAlgAndValueSHA256]
+hashAlg=SEQUENCE:sha256_alg
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
+[HashAlgAndValueSHA1]
+hashAlg=SEQUENCE:sha1_alg
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
+[sha256_alg]
+algorithm=OID:sha256
+[sha1_alg]
+algorithm=OID:sha1
+[URI]
+uri=IA5STRING:@LOGO_URI@
+[LogotypeImageInfo]
+# default value color(1), component optional
+#type=IMP:0,INTEGER:1
+fileSize=INTEGER:7549
+xSize=INTEGER:128
+ySize=INTEGER:80
+language=IMP:4,IA5STRING:zxx
+
+[ crl_ext ]
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ v3_OCSP ]
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = OCSPSigning
+
+[ ext_client ]
+
+basicConstraints=CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
+#@ALTNAME@
+extendedKeyUsage = clientAuth
+
+[ ext_server ]
+
+# Hotspot 2.0 PKI requirements
+basicConstraints=critical, CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
+#@ALTNAME@
+extendedKeyUsage = critical, serverAuth
+keyUsage = critical, keyEncipherment
diff --git a/contrib/wpa/hs20/server/ca/setup.sh b/contrib/wpa/hs20/server/ca/setup.sh
new file mode 100755
index 000000000000..78abcccff455
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/setup.sh
@@ -0,0 +1,209 @@
+#!/bin/sh
+
+if [ -z "$OPENSSL" ]; then
+ OPENSSL=openssl
+fi
+export OPENSSL_CONF=$PWD/openssl.cnf
+PASS=whatever
+if [ -z "$DOMAIN" ]; then
+ DOMAIN=w1.fi
+fi
+COMPANY=w1.fi
+OPER_ENG="engw1.fi TESTING USE"
+OPER_FI="finw1.fi TESTIKÄYTTÖ"
+CNR="Hotspot 2.0 Trust Root CA - 99"
+CNO="ocsp.$DOMAIN"
+CNV="osu-revoked.$DOMAIN"
+CNOC="osu-client.$DOMAIN"
+OSU_SERVER_HOSTNAME="osu.$DOMAIN"
+DEBUG=0
+OCSP_URI="http://$CNO:8888/"
+LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
+LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
+LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
+
+# Command line overrides
+USAGE=$( cat <<EOF
+Usage:\n
+# -c: Company name, used to generate Subject name CN for Intermediate CA\n
+# -C: Subject name CN of the Root CA ($CNR)\n
+# -D: Enable debugging (set -x, etc)\n
+# -g: Logo sha1 hash ($LOGO_HASH1)\n
+# -G: Logo sha256 hash ($LOGO_HASH256)\n
+# -h: Show this help message\n
+# -l: Logo URI ($LOGO_URI)\n
+# -m: Domain ($DOMAIN)\n
+# -o: Subject name CN for OSU-Client Server ($CNOC)\n
+# -O: Subject name CN for OCSP Server ($CNO)\n
+# -p: passphrase for private keys ($PASS)\n
+# -r: Operator-english ($OPER_ENG)\n
+# -R: Operator-finish ($OPER_FI)\n
+# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
+# -u: OCSP-URI ($OCSP_URI)\n
+# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
+EOF
+)
+
+while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
+ do
+ case $flag in
+ c) COMPANY=$OPTARG;;
+ C) CNR=$OPTARG;;
+ D) DEBUG=1;;
+ g) LOGO_HASH1=$OPTARG;;
+ G) LOGO_HASH256=$OPTARG;;
+ h) echo -e $USAGE; exit 0;;
+ l) LOGO_URI=$OPTARG;;
+ m) DOMAIN=$OPTARG;;
+ o) CNOC=$OPTARG;;
+ O) CNO=$OPTARG;;
+ p) PASS=$OPTARG;;
+ r) OPER_ENG=$OPTARG;;
+ R) OPER_FI=$OPTARG;;
+ S) OSU_SERVER_HOSTNAME=$OPTARG;;
+ u) OCSP_URI=$OPTARG;;
+ V) CNV=$OPTARG;;
+ *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
+ esac
+done
+
+fail()
+{
+ echo "$*"
+ exit 1
+}
+
+echo
+echo "---[ Root CA ]----------------------------------------------------------"
+echo
+
+if [ $DEBUG = 1 ]
+then
+ set -x
+fi
+
+# Set the passphrase and some other common config accordingly.
+cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
+ > my-openssl-root.cnf
+
+cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
+sed "s,@OCSP_URI@,$OCSP_URI," |
+sed "s,@LOGO_URI@,$LOGO_URI," |
+sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
+sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
+sed "s/@DOMAIN@/$DOMAIN/" \
+ > my-openssl.cnf
+
+
+cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
+mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
+touch rootCA/index.txt
+if [ -e rootCA/private/cakey.pem ]; then
+ echo " * Use existing Root CA"
+else
+ echo " * Generate Root CA private key"
+ $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
+ echo " * Sign Root CA certificate"
+ $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
+ $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
+ sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
+fi
+if [ ! -e rootCA/crlnumber ]; then
+ echo 00 > rootCA/crlnumber
+fi
+
+echo
+echo "---[ Intermediate CA ]--------------------------------------------------"
+echo
+
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
+mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
+touch demoCA/index.txt
+if [ -e demoCA/private/cakey.pem ]; then
+ echo " * Use existing Intermediate CA"
+else
+ echo " * Generate Intermediate CA private key"
+ $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate Intermediate CA private key"
+ echo " * Sign Intermediate CA certificate"
+ $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
+ # horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
+ openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
+ $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
+ sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
+fi
+if [ ! -e demoCA/crlnumber ]; then
+ echo 00 > demoCA/crlnumber
+fi
+
+echo
+echo "OCSP responder"
+echo
+
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
+
+echo
+echo "---[ Server - to be revoked ] ------------------------------------------"
+echo
+
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
+$OPENSSL ca -revoke server-revoked.pem -key $PASS
+
+echo
+echo "---[ Server - with client ext key use ] ---------------------------------"
+echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
+echo
+
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
+
+echo
+echo "---[ User ]-------------------------------------------------------------"
+echo
+
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
+
+echo
+echo "---[ Server ]-----------------------------------------------------------"
+echo
+
+ALT="DNS:$OSU_SERVER_HOSTNAME"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
+
+cat my-openssl.cnf |
+ sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
+ sed "s/^##organizationalUnitName/organizationalUnitName/" |
+ sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
+ sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
+ > openssl.cnf.tmp
+echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail "Failed to generate server request"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -out server.pem -key $PASS -days 730 -extensions ext_server -policy policy_osu_server || fail "Failed to sign server certificate"
+
+#dump logotype details for debugging
+$OPENSSL x509 -in server.pem -out server.der -outform DER
+openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' | xxd -r -p > logo.der
+openssl asn1parse -in logo.der -inform DER > logo.asn1
+
+
+echo
+echo "---[ CRL ]---------------------------------------------------------------"
+echo
+
+$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
+
+echo
+echo "---[ Verify ]------------------------------------------------------------"
+echo
+
+$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem
+$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem *.pem
+
+cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem
diff --git a/contrib/wpa/hs20/server/ca/w1fi_logo.png b/contrib/wpa/hs20/server/ca/w1fi_logo.png
new file mode 100644
index 000000000000..ac7c259fff2e
--- /dev/null
+++ b/contrib/wpa/hs20/server/ca/w1fi_logo.png
Binary files differ
diff --git a/contrib/wpa/hs20/server/hs20-osu-server.txt b/contrib/wpa/hs20/server/hs20-osu-server.txt
new file mode 100644
index 000000000000..22478ad9d2cb
--- /dev/null
+++ b/contrib/wpa/hs20/server/hs20-osu-server.txt
@@ -0,0 +1,262 @@
+Hotspot 2.0 OSU server
+======================
+
+The information in this document is based on the assumption that Ubuntu
+16.04 server (64-bit) distribution is used and the web server is
+Apache2. Neither of these are requirements for the installation, but if
+other combinations are used, the package names and configuration
+parameters may need to be adjusted.
+
+NOTE: This implementation and the example configuration here is meant
+only for testing purposes in a lab environment. This design is not
+secure to be installed in a publicly available Internet server without
+considerable amount of modification and review for security issues.
+
+
+Build dependencies
+------------------
+
+Ubuntu 16.04 server
+- default installation
+- upgraded to latest package versions
+ sudo apt-get update
+ sudo apt-get upgrade
+
+Packages needed for running the service:
+ sudo apt-get install sqlite3
+ sudo apt-get install apache2
+ sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
+
+Additional packages needed for building the components:
+ sudo apt-get install build-essential
+ sudo apt-get install libsqlite3-dev
+ sudo apt-get install libssl-dev
+ sudo apt-get install libxml2-dev
+
+
+Installation location
+---------------------
+
+Select a location for the installation root directory. The example here
+assumes /home/user/hs20-server to be used, but this can be changed by
+editing couple of files as indicated below.
+
+sudo mkdir -p /home/user/hs20-server
+sudo chown $USER /home/user/hs20-server
+mkdir -p /home/user/hs20-server/spp
+mkdir -p /home/user/hs20-server/AS
+
+
+Build
+-----
+
+# hostapd as RADIUS server
+cd hostapd
+
+#example build configuration
+cat > .config <<EOF
+CONFIG_DRIVER_NONE=y
+CONFIG_PKCS12=y
+CONFIG_RADIUS_SERVER=y
+CONFIG_EAP=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=y
+CONFIG_EAP_AKA_PRIME=y
+CONFIG_SQLITE=y
+CONFIG_HS20=y
+EOF
+
+make hostapd hlr_auc_gw
+cp hostapd hlr_auc_gw /home/user/hs20-server/AS
+
+# build hs20_spp_server
+cd ../hs20/server
+make clean
+make
+cp hs20_spp_server /home/user/hs20-server/spp
+# prepare database (web server user/group needs to have write access)
+mkdir -p /home/user/hs20-server/AS/DB
+sudo chgrp www-data /home/user/hs20-server/AS/DB
+sudo chmod g+w /home/user/hs20-server/AS/DB
+sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt
+sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db
+sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db
+# add example configuration (note: need to update URLs to match the system)
+sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt
+
+# copy PHP scripts
+# Modify config.php if different installation directory is used.
+# Modify PHP scripts to get the desired behavior for user interaction (or use
+# the examples as-is for initial testing).
+cp -r www /home/user/hs20-server
+
+# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
+# inserted within the BODY section of the page).
+cat > /home/user/hs20-server/terms-and-conditions <<EOF
+<P>Terms and conditions..</P>
+EOF
+
+# Build local keys and certs
+cd ca
+# Display help options.
+./setup.sh -h
+
+# Remove old keys, fill in appropriate values, and generate your keys.
+# For instance:
+./clean.sh
+rm -fr rootCA"
+old_hostname=myserver.local
+./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
+ -o $old_hostname-osu-client \
+ -O $old_hostname-oscp -p lanforge -S $old_hostname \
+ -V $old_hostname-osu-revoked \
+ -m local -u http://$old_hostname:8888/
+
+# Configure subscription policies
+mkdir -p /home/user/hs20-server/spp/policy
+cat > /home/user/hs20-server/spp/policy/default.xml <<EOF
+<Policy>
+ <PolicyUpdate>
+ <UpdateInterval>30</UpdateInterval>
+ <UpdateMethod>ClientInitiated</UpdateMethod>
+ <Restriction>Unrestricted</Restriction>
+ <URI>https://policy-server.osu.example.com/hs20/spp.php</URI>
+ </PolicyUpdate>
+</Policy>
+EOF
+
+
+# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files
+
+# XML schema for SPP
+# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd
+
+# OMA DM Device Description Framework DTD
+# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd
+# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd
+
+
+# Configure RADIUS authentication service
+# Note: Change the URL to match the setup
+# Note: Install AAA server key/certificate and root CA in Key directory
+
+cat > /home/user/hs20-server/AS/as-sql.conf <<EOF
+driver=none
+radius_server_clients=as.radius_clients
+eap_server=1
+eap_user_file=sqlite:DB/eap_user.db
+ca_cert=Key/ca.pem
+server_cert=Key/server.pem
+private_key=Key/server.key
+private_key_passwd=passphrase
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db
+subscr_remediation_url=https://subscription-server.osu.example.com/hs20/spp.php
+EOF
+
+# Set RADIUS passphrase for the APs
+# Note: Modify to match the setup
+cat > /home/user/hs20-server/AS/as.radius_clients <<EOF
+0.0.0.0/0 radius
+EOF
+
+
+Start RADIUS authentication server
+----------------------------------
+
+cd /home/user/hs20-server/AS
+./hostapd -B as-sql.conf
+
+
+OSEN RADIUS server configuration notes
+
+The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
+configuration in it. For example:
+
+# hostapd-radius config for the radius used by the OSEN AP
+interface=eth0#0
+driver=none
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+ctrl_interface=/var/run/hostapd
+ctrl_interface_group=0
+eap_server=1
+eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
+server_id=ben-ota-2-osen
+radius_server_auth_port=1811
+radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
+
+ca_cert=/home/user/hs20-server/ca/ca.pem
+server_cert=/home/user/hs20-server/ca/server.pem
+private_key=/home/user/hs20-server/ca/server.key
+private_key_passwd=whatever
+
+ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
+
+The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
+similar to this, and should coorelate with the osu_nai entry in
+the non-OSEN VAP config file. For instance:
+
+# cat hostapd-osen.eap_user
+# For OSEN authentication (Hotspot 2.0 Release 2)
+"osen@w1.fi" WFA-UNAUTH-TLS
+
+
+# Run OCSP server:
+cd /home/user/hs20-server/ca
+./ocsp-responder.sh&
+
+# Update cache (This should be run periodically)
+./ocsp-update-cache.sh
+
+
+Configure web server
+--------------------
+
+Edit /etc/apache2/sites-available/default-ssl
+
+Add following block just before "SSL Engine Switch" line":
+
+ Alias /hs20/ "/home/user/hs20-server/www/"
+ <Directory "/home/user/hs20-server/www/">
+ Options Indexes MultiViews FollowSymLinks
+ AllowOverride None
+ Require all granted
+ SSLOptions +StdEnvVars
+ </Directory>
+
+Update SSL configuration to use the OSU server certificate/key.
+They keys and certs are called 'server.key' and 'server.pem' from
+ca/setup.sh.
+
+To support subscription remediation using client certificates, set
+"SSLVerifyClient optional" and configure the trust root CA(s) for the
+client certificates with SSLCACertificateFile.
+
+Enable default-ssl site and restart Apache2:
+ sudo a2ensite default-ssl
+ sudo a2enmod ssl
+ sudo service apache2 restart
+
+
+Management UI
+-------------
+
+The sample PHP scripts include a management UI for testing
+purposes. That is available at https://<server>/hs20/users.php
+
+
+AP configuration
+----------------
+
+APs can now be configured to use the OSU server as the RADIUS
+authentication server. In addition, the OSU Provider List ANQP element
+should be configured to use the SPP (SOAP+XML) option and with the
+following Server URL:
+https://<server>/hs20/spp.php/signup?realm=example.com
diff --git a/contrib/wpa/hs20/server/hs20_spp_server.c b/contrib/wpa/hs20/server/hs20_spp_server.c
new file mode 100644
index 000000000000..347c40a73d6a
--- /dev/null
+++ b/contrib/wpa/hs20/server/hs20_spp_server.c
@@ -0,0 +1,207 @@
+/*
+ * Hotspot 2.0 SPP server - standalone version
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <time.h>
+#include <sqlite3.h>
+
+#include "common.h"
+#include "common/version.h"
+#include "xml-utils.h"
+#include "spp_server.h"
+
+
+static void write_timestamp(FILE *f)
+{
+ time_t t;
+ struct tm *tm;
+
+ time(&t);
+ tm = localtime(&t);
+
+ fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+
+void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (ctx->debug_log == NULL)
+ return;
+
+ write_timestamp(ctx->debug_log);
+ va_start(ap, fmt);
+ vfprintf(ctx->debug_log, fmt, ap);
+ va_end(ap);
+
+ fprintf(ctx->debug_log, "\n");
+}
+
+
+void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
+{
+ char *str;
+
+ if (ctx->debug_log == NULL)
+ return;
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+
+ write_timestamp(ctx->debug_log);
+ fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
+ os_free(str);
+}
+
+
+static int process(struct hs20_svc *ctx)
+{
+ int dmacc = 0;
+ xml_node_t *soap, *spp, *resp;
+ char *user, *realm, *post, *str;
+
+ ctx->addr = getenv("HS20ADDR");
+ if (ctx->addr)
+ debug_print(ctx, 1, "Connection from %s", ctx->addr);
+ ctx->test = getenv("HS20TEST");
+ if (ctx->test)
+ debug_print(ctx, 1, "Requested test functionality: %s",
+ ctx->test);
+
+ user = getenv("HS20USER");
+ if (user && strlen(user) == 0)
+ user = NULL;
+ realm = getenv("HS20REALM");
+ if (realm == NULL) {
+ debug_print(ctx, 1, "HS20REALM not set");
+ return -1;
+ }
+ post = getenv("HS20POST");
+ if (post == NULL) {
+ debug_print(ctx, 1, "HS20POST not set");
+ return -1;
+ }
+
+ ctx->imsi = getenv("HS20IMSI");
+ if (ctx->imsi)
+ debug_print(ctx, 1, "IMSI %s", ctx->imsi);
+
+ ctx->eap_method = getenv("HS20EAPMETHOD");
+ if (ctx->eap_method)
+ debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
+
+ ctx->id_hash = getenv("HS20IDHASH");
+ if (ctx->id_hash)
+ debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
+
+ soap = xml_node_from_buf(ctx->xml, post);
+ if (soap == NULL) {
+ debug_print(ctx, 1, "Could not parse SOAP data");
+ return -1;
+ }
+ debug_dump_node(ctx, "Received SOAP message", soap);
+ spp = soap_get_body(ctx->xml, soap);
+ if (spp == NULL) {
+ debug_print(ctx, 1, "Could not get SPP message");
+ xml_node_free(ctx->xml, soap);
+ return -1;
+ }
+ debug_dump_node(ctx, "Received SPP message", spp);
+
+ resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
+ xml_node_free(ctx->xml, soap);
+ if (resp == NULL && user == NULL) {
+ debug_print(ctx, 1, "Request HTTP authentication");
+ return 2; /* Request authentication */
+ }
+ if (resp == NULL) {
+ debug_print(ctx, 1, "No response");
+ return -1;
+ }
+
+ soap = soap_build_envelope(ctx->xml, resp);
+ if (soap == NULL) {
+ debug_print(ctx, 1, "SOAP envelope building failed");
+ return -1;
+ }
+ str = xml_node_to_str(ctx->xml, soap);
+ xml_node_free(ctx->xml, soap);
+ if (str == NULL) {
+ debug_print(ctx, 1, "Could not get node string");
+ return -1;
+ }
+ printf("%s", str);
+ free(str);
+
+ return 0;
+}
+
+
+static void usage(void)
+{
+ printf("usage:\n"
+ "hs20_spp_server -r<root directory> [-f<debug log>]\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct hs20_svc ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ for (;;) {
+ int c = getopt(argc, argv, "f:r:v");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'f':
+ if (ctx.debug_log)
+ break;
+ ctx.debug_log = fopen(optarg, "a");
+ if (ctx.debug_log == NULL) {
+ printf("Could not write to %s\n", optarg);
+ return -1;
+ }
+ break;
+ case 'r':
+ ctx.root_dir = optarg;
+ break;
+ case 'v':
+ printf("hs20_spp_server v%s\n", VERSION_STR);
+ return 0;
+ default:
+ usage();
+ return -1;
+ }
+ }
+ if (ctx.root_dir == NULL) {
+ usage();
+ return -1;
+ }
+ ctx.xml = xml_node_init_ctx(&ctx, NULL);
+ if (ctx.xml == NULL)
+ return -1;
+ if (hs20_spp_server_init(&ctx) < 0) {
+ xml_node_deinit_ctx(ctx.xml);
+ return -1;
+ }
+
+ ret = process(&ctx);
+ debug_print(&ctx, 1, "process() --> %d", ret);
+
+ xml_node_deinit_ctx(ctx.xml);
+ hs20_spp_server_deinit(&ctx);
+ if (ctx.debug_log)
+ fclose(ctx.debug_log);
+
+ return ret;
+}
diff --git a/contrib/wpa/hs20/server/spp_server.c b/contrib/wpa/hs20/server/spp_server.c
new file mode 100644
index 000000000000..a50e9074f7b4
--- /dev/null
+++ b/contrib/wpa/hs20/server/spp_server.c
@@ -0,0 +1,2933 @@
+/*
+ * Hotspot 2.0 SPP server
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <sqlite3.h>
+
+#include "common.h"
+#include "base64.h"
+#include "md5_i.h"
+#include "xml-utils.h"
+#include "spp_server.h"
+
+
+#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
+
+#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
+#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
+#define URN_OMA_DM_DMACC "urn:oma:mo:oma-dm-dmacc:1.0"
+#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
+
+
+/* TODO: timeout to expire sessions */
+
+enum hs20_session_operation {
+ NO_OPERATION,
+ UPDATE_PASSWORD,
+ CONTINUE_SUBSCRIPTION_REMEDIATION,
+ CONTINUE_POLICY_UPDATE,
+ USER_REMEDIATION,
+ SUBSCRIPTION_REGISTRATION,
+ POLICY_REMEDIATION,
+ POLICY_UPDATE,
+ FREE_REMEDIATION,
+ CLEAR_REMEDIATION,
+ CERT_REENROLL,
+};
+
+
+static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *field);
+static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
+ const char *field);
+static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
+ const char *realm, int use_dmacc);
+static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *user,
+ const char *realm,
+ int add_est_user);
+
+
+static int db_add_session(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *pw,
+ const char *redirect_uri,
+ enum hs20_session_operation operation,
+ const u8 *mac_addr)
+{
+ char *sql;
+ int ret = 0;
+ char addr[20];
+
+ if (mac_addr)
+ snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
+ else
+ addr[0] = '\0';
+ sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
+ "operation,password,redirect_uri,mac_addr,test) "
+ "VALUES "
+ "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
+ "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
+ sessionid, user ? user : "", realm ? realm : "",
+ operation, pw ? pw : "",
+ redirect_uri ? redirect_uri : "",
+ addr, ctx->test);
+ if (sql == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session entry into sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ ret = -1;
+ }
+ sqlite3_free(sql);
+ return ret;
+}
+
+
+static void db_update_session_password(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *sessionid,
+ const char *pw)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
+ "user=%Q AND realm=%Q",
+ pw, sessionid, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update session password: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_update_session_machine_managed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *sessionid,
+ const int pw_mm)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
+ pw_mm ? "1" : "0", sessionid, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to update session machine_managed: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
+ "user=%Q AND realm=%Q",
+ str, sessionid, user, realm);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session pps: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
+ str, sessionid);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session devinfo: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_devdetail(struct hs20_svc *ctx,
+ const char *sessionid,
+ xml_node_t *node)
+{
+ char *str;
+ char *sql;
+
+ str = xml_node_to_str(ctx->xml, node);
+ if (str == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
+ str, sessionid);
+ free(str);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session devdetail: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
+ const char *username, const char *password)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
+ username, password, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session DMAcc: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_eap_method(struct hs20_svc *ctx,
+ const char *sessionid,
+ const char *method)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
+ method, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session EAP method: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
+ const char *id_hash)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
+ id_hash, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session ID hash: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_remove_session(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid)
+{
+ char *sql;
+
+ if (user == NULL || realm == NULL) {
+ sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
+ "id=%Q", sessionid);
+ } else {
+ sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
+ "user=%Q AND realm=%Q AND id=%Q",
+ user, realm, sessionid);
+ }
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to delete session entry from "
+ "sqlite database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void hs20_eventlog(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *notes,
+ const char *dump)
+{
+ char *sql;
+ char *user_buf = NULL, *realm_buf = NULL;
+
+ debug_print(ctx, 1, "eventlog: %s", notes);
+
+ if (user == NULL) {
+ user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
+ "user");
+ user = user_buf;
+ realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
+ "realm");
+ realm = realm_buf;
+ }
+
+ sql = sqlite3_mprintf("INSERT INTO eventlog"
+ "(user,realm,sessionid,timestamp,notes,dump,addr)"
+ " VALUES (%Q,%Q,%Q,"
+ "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
+ "%Q,%Q,%Q)",
+ user, realm, sessionid, notes,
+ dump ? dump : "", ctx->addr ? ctx->addr : "");
+ free(user_buf);
+ free(realm_buf);
+ if (sql == NULL)
+ return;
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void hs20_eventlog_node(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *sessionid, const char *notes,
+ xml_node_t *node)
+{
+ char *str;
+
+ if (node)
+ str = xml_node_to_str(ctx->xml, node);
+ else
+ str = NULL;
+ hs20_eventlog(ctx, user, realm, sessionid, notes, str);
+ free(str);
+}
+
+
+static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *name,
+ const char *str)
+{
+ char *sql;
+ if (user == NULL || realm == NULL || name == NULL)
+ return;
+ sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ name, str, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
+ "database: %s", sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_update_mo(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *name, xml_node_t *mo)
+{
+ char *str;
+
+ str = xml_node_to_str(ctx->xml, mo);
+ if (str == NULL)
+ return;
+
+ db_update_mo_str(ctx, user, realm, name, str);
+ free(str);
+}
+
+
+static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
+ const char *name, const char *value)
+{
+ xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
+}
+
+
+static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *parent, const char *name,
+ const char *field)
+{
+ char *val;
+ val = db_get_osu_config_val(ctx, realm, field);
+ xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+ os_free(val);
+}
+
+
+static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *parent, const char *name,
+ const char *field)
+{
+ char *val;
+
+ val = db_get_osu_config_val(ctx, realm, field);
+ if (val) {
+ size_t len;
+
+ len = os_strlen(val);
+ if (len > 0) {
+ if (val[len - 1] == '0')
+ val[len - 1] = '1';
+ else
+ val[len - 1] = '0';
+ }
+ }
+ xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+ os_free(val);
+}
+
+
+static int new_password(char *buf, int buflen)
+{
+ int i;
+
+ if (buflen < 1)
+ return -1;
+ buf[buflen - 1] = '\0';
+ if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
+ return -1;
+
+ for (i = 0; i < buflen - 1; i++) {
+ unsigned char val = buf[i];
+ val %= 2 * 26 + 10;
+ if (val < 26)
+ buf[i] = 'a' + val;
+ else if (val < 2 * 26)
+ buf[i] = 'A' + val - 26;
+ else
+ buf[i] = '0' + val - 2 * 26;
+ }
+
+ return 0;
+}
+
+
+struct get_db_field_data {
+ const char *field;
+ char *value;
+};
+
+
+static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct get_db_field_data *data = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
+ os_free(data->value);
+ data->value = os_strdup(argv[i]);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static char * db_get_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *field, int dmacc)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ field, dmacc ? "osu_user" : "identity",
+ user, realm);
+ if (cmd == NULL)
+ return NULL;
+ memset(&data, 0, sizeof(data));
+ data.field = field;
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "Could not find user '%s'", user);
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
+ "value='%s'", user, realm, field, dmacc, data.value);
+
+ return data.value;
+}
+
+
+static int db_update_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *field,
+ const char *val, int dmacc)
+{
+ char *cmd;
+ int ret;
+
+ cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ field, val, dmacc ? "osu_user" : "identity", user,
+ realm);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to update user in sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ ret = -1;
+ } else {
+ debug_print(ctx, 1,
+ "DB: user='%s' realm='%s' field='%s' set to '%s'",
+ user, realm, field, val);
+ ret = 0;
+ }
+ sqlite3_free(cmd);
+
+ return ret;
+}
+
+
+static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *field)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ if (user == NULL || realm == NULL) {
+ cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
+ "id=%Q", field, session_id);
+ } else {
+ cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
+ "user=%Q AND realm=%Q AND id=%Q",
+ field, user, realm, session_id);
+ }
+ if (cmd == NULL)
+ return NULL;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ memset(&data, 0, sizeof(data));
+ data.field = field;
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "DB: Could not find session %s: %s",
+ session_id, sqlite3_errmsg(ctx->db));
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: return '%s'", data.value);
+ return data.value;
+}
+
+
+static int update_password(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *pw, int dmacc)
+{
+ char *cmd;
+
+ cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
+ "remediation='' "
+ "WHERE %s=%Q AND phase2=1",
+ pw, dmacc ? "osu_user" : "identity",
+ user);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update database for user '%s'",
+ user);
+ }
+ sqlite3_free(cmd);
+
+ return 0;
+}
+
+
+static int clear_remediation(struct hs20_svc *ctx, const char *user,
+ const char *realm, int dmacc)
+{
+ char *cmd;
+
+ cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
+ dmacc ? "osu_user" : "identity",
+ user);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update database for user '%s'",
+ user);
+ }
+ sqlite3_free(cmd);
+
+ return 0;
+}
+
+
+static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
+ if (node == NULL)
+ return -1;
+
+ add_text_node(ctx, node, "EAPType", "21");
+ add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
+
+ return 0;
+}
+
+
+static xml_node_t * build_username_password(struct hs20_svc *ctx,
+ xml_node_t *parent,
+ const char *user, const char *pw)
+{
+ xml_node_t *node;
+ char *b64;
+ size_t len;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
+ if (node == NULL)
+ return NULL;
+
+ add_text_node(ctx, node, "Username", user);
+
+ b64 = base64_encode(pw, strlen(pw), NULL);
+ if (b64 == NULL)
+ return NULL;
+ len = os_strlen(b64);
+ if (len > 0 && b64[len - 1] == '\n')
+ b64[len - 1] = '\0';
+ add_text_node(ctx, node, "Password", b64);
+ free(b64);
+
+ return node;
+}
+
+
+static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
+ const char *user, const char *pw,
+ int machine_managed)
+{
+ xml_node_t *node;
+
+ node = build_username_password(ctx, cred, user, pw);
+ if (node == NULL)
+ return -1;
+
+ add_text_node(ctx, node, "MachineManaged",
+ machine_managed ? "TRUE" : "FALSE");
+ add_text_node(ctx, node, "SoftTokenApp", "");
+ add_eap_ttls(ctx, node);
+
+ return 0;
+}
+
+
+static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
+{
+ char str[30];
+ time_t now;
+ struct tm tm;
+
+ time(&now);
+ gmtime_r(&now, &tm);
+ snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
+}
+
+
+static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *pw, int machine_managed)
+{
+ xml_node_t *cred;
+
+ cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
+ if (cred == NULL) {
+ debug_print(ctx, 1, "Failed to create Credential node");
+ return NULL;
+ }
+ add_creation_date(ctx, cred);
+ if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return cred;
+}
+
+
+static xml_node_t * build_credential(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ char *new_pw, size_t new_pw_len)
+{
+ if (new_password(new_pw, new_pw_len) < 0)
+ return NULL;
+ debug_print(ctx, 1, "Update password to '%s'", new_pw);
+ return build_credential_pw(ctx, user, realm, new_pw, 1);
+}
+
+
+static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *cert_fingerprint)
+{
+ xml_node_t *cred, *cert;
+
+ cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
+ if (cred == NULL) {
+ debug_print(ctx, 1, "Failed to create Credential node");
+ return NULL;
+ }
+ add_creation_date(ctx, cred);
+ cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
+ add_text_node(ctx, cert, "CertificateType", "x509v3");
+ add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return cred;
+}
+
+
+static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
+ xml_namespace_t **ret_ns,
+ const char *session_id,
+ const char *status,
+ const char *error_code)
+{
+ xml_node_t *spp_node = NULL;
+ xml_namespace_t *ns;
+
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppPostDevDataResponse");
+ if (spp_node == NULL)
+ return NULL;
+ if (ret_ns)
+ *ret_ns = ns;
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
+
+ if (error_code) {
+ xml_node_t *node;
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ if (node)
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ error_code);
+ }
+
+ return spp_node;
+}
+
+
+static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
+ xml_namespace_t *ns, const char *uri,
+ xml_node_t *upd_node)
+{
+ xml_node_t *node, *tnds;
+ char *str;
+
+ tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
+ if (!tnds)
+ return -1;
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (str == NULL)
+ return -1;
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
+ free(str);
+
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
+
+ return 0;
+}
+
+
+static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
+ const char *subrem_id,
+ char *uri, size_t uri_size)
+{
+ char fname[200];
+ char *buf, *buf2, *pos;
+ size_t len;
+ xml_node_t *node;
+
+ os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
+ ctx->root_dir, subrem_id);
+ debug_print(ctx, 1, "Use subrem file %s", fname);
+
+ buf = os_readfile(fname, &len);
+ if (!buf)
+ return NULL;
+ buf2 = os_realloc(buf, len + 1);
+ if (!buf2) {
+ os_free(buf);
+ return NULL;
+ }
+ buf = buf2;
+ buf[len] = '\0';
+
+ pos = os_strchr(buf, '\n');
+ if (!pos) {
+ os_free(buf);
+ return NULL;
+ }
+ *pos++ = '\0';
+ os_strlcpy(uri, buf, uri_size);
+
+ node = xml_node_from_buf(ctx->xml, pos);
+ os_free(buf);
+
+ return node;
+}
+
+
+static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id,
+ int machine_rem, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *cred;
+ char buf[400];
+ char new_pw[33];
+ char *status;
+ char *cert;
+
+ cert = db_get_val(ctx, user, realm, "cert", dmacc);
+ if (cert && cert[0] == '\0') {
+ os_free(cert);
+ cert = NULL;
+ }
+ if (cert) {
+ char *subrem;
+
+ /* No change needed in PPS MO unless specifically asked to */
+ cred = NULL;
+ buf[0] = '\0';
+
+ subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
+ if (subrem && subrem[0]) {
+ cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
+ if (!cred) {
+ debug_print(ctx, 1,
+ "Could not create updateNode from subrem file");
+ os_free(subrem);
+ os_free(cert);
+ return NULL;
+ }
+ }
+ os_free(subrem);
+ } else {
+ char *real_user = NULL;
+ char *pw;
+
+ if (dmacc) {
+ real_user = db_get_val(ctx, user, realm, "identity",
+ dmacc);
+ if (!real_user) {
+ debug_print(ctx, 1,
+ "Could not find user identity for dmacc user '%s'",
+ user);
+ return NULL;
+ }
+ }
+
+ pw = db_get_session_val(ctx, user, realm, session_id,
+ "password");
+ if (pw && pw[0]) {
+ debug_print(ctx, 1, "New password from the user: '%s'",
+ pw);
+ snprintf(new_pw, sizeof(new_pw), "%s", pw);
+ free(pw);
+ cred = build_credential_pw(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, 0);
+ } else {
+ cred = build_credential(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, sizeof(new_pw));
+ }
+
+ free(real_user);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ os_free(cert);
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL) {
+ debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ os_free(cert);
+ return NULL;
+ }
+
+ if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
+ (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
+ debug_print(ctx, 1, "Could not add update node");
+ xml_node_free(ctx->xml, spp_node);
+ os_free(cert);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ machine_rem ? "machine remediation" :
+ "user remediation", cred);
+ xml_node_free(ctx->xml, cred);
+
+ if (cert) {
+ debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CLEAR_REMEDIATION, NULL);
+ } else {
+ debug_print(ctx, 1, "Request DB password update on success "
+ "notification");
+ db_add_session(ctx, user, realm, session_id, new_pw, NULL,
+ UPDATE_PASSWORD, NULL);
+ }
+ os_free(cert);
+
+ return spp_node;
+}
+
+
+static xml_node_t * machine_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id, int dmacc)
+{
+ return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
+}
+
+
+static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id)
+{
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CERT_REENROLL, NULL);
+ return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
+}
+
+
+static xml_node_t * policy_remediation(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *policy;
+ char buf[400];
+ const char *status;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires policy remediation", NULL);
+
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ POLICY_REMEDIATION, NULL);
+
+ policy = build_policy(ctx, user, realm, dmacc);
+ if (!policy) {
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "No update available at this time", NULL);
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "policy update (sub rem)", policy);
+ xml_node_free(ctx->xml, policy);
+
+ return spp_node;
+}
+
+
+static xml_node_t * browser_remediation(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *redirect_uri,
+ const char *uri)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *exec_node;
+
+ if (redirect_uri == NULL) {
+ debug_print(ctx, 1, "Missing redirectURI attribute for user "
+ "remediation");
+ return NULL;
+ }
+ debug_print(ctx, 1, "redirectURI %s", redirect_uri);
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+ xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
+ uri);
+ return spp_node;
+}
+
+
+static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
+ const char *realm, const char *session_id,
+ const char *redirect_uri)
+{
+ char uri[300], *val;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires user remediation", NULL);
+ val = db_get_osu_config_val(ctx, realm, "remediation_url");
+ if (val == NULL)
+ return NULL;
+
+ db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
+ USER_REMEDIATION, NULL);
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ return browser_remediation(ctx, session_id, redirect_uri, uri);
+}
+
+
+static xml_node_t * free_remediation(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id,
+ const char *redirect_uri)
+{
+ char uri[300], *val;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "requires free/public account remediation", NULL);
+ val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
+ if (val == NULL)
+ return NULL;
+
+ db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
+ FREE_REMEDIATION, NULL);
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ return browser_remediation(ctx, session_id, redirect_uri, uri);
+}
+
+
+static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id)
+{
+ const char *status;
+
+ hs20_eventlog(ctx, user, realm, session_id,
+ "no subscription mediation available", NULL);
+
+ status = "No update available at this time";
+ return build_post_dev_data_response(ctx, NULL, session_id, status,
+ NULL);
+}
+
+
+static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc,
+ const char *redirect_uri)
+{
+ char *type, *identity;
+ xml_node_t *ret;
+ char *free_account;
+
+ identity = db_get_val(ctx, user, realm, "identity", dmacc);
+ if (identity == NULL || strlen(identity) == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "user not found in database for remediation",
+ NULL);
+ os_free(identity);
+ return build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred",
+ "Not found");
+ }
+ os_free(identity);
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ if (free_account && strcmp(free_account, user) == 0) {
+ free(free_account);
+ return no_sub_rem(ctx, user, realm, session_id);
+ }
+ free(free_account);
+
+ type = db_get_val(ctx, user, realm, "remediation", dmacc);
+ if (type && strcmp(type, "free") != 0) {
+ char *val;
+ int shared = 0;
+ val = db_get_val(ctx, user, realm, "shared", dmacc);
+ if (val)
+ shared = atoi(val);
+ free(val);
+ if (shared) {
+ free(type);
+ return no_sub_rem(ctx, user, realm, session_id);
+ }
+ }
+ if (type && strcmp(type, "user") == 0)
+ ret = user_remediation(ctx, user, realm, session_id,
+ redirect_uri);
+ else if (type && strcmp(type, "free") == 0)
+ ret = free_remediation(ctx, user, realm, session_id,
+ redirect_uri);
+ else if (type && strcmp(type, "policy") == 0)
+ ret = policy_remediation(ctx, user, realm, session_id, dmacc);
+ else if (type && strcmp(type, "machine") == 0)
+ ret = machine_remediation(ctx, user, realm, session_id, dmacc);
+ else if (type && strcmp(type, "reenroll") == 0)
+ ret = cert_reenroll(ctx, user, realm, session_id);
+ else
+ ret = no_sub_rem(ctx, user, realm, session_id);
+ free(type);
+
+ return ret;
+}
+
+
+static xml_node_t * read_policy_file(struct hs20_svc *ctx,
+ const char *policy_id)
+{
+ char fname[200];
+
+ snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
+ ctx->root_dir, policy_id);
+ debug_print(ctx, 1, "Use policy file %s", fname);
+
+ return node_from_file(ctx->xml, fname);
+}
+
+
+static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *policy)
+{
+ xml_node_t *node;
+ char *url;
+
+ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
+ if (!node)
+ return;
+
+ url = db_get_osu_config_val(ctx, realm, "policy_url");
+ if (!url)
+ return;
+ xml_node_set_text(ctx->xml, node, url);
+ free(url);
+}
+
+
+static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
+ const char *realm, int use_dmacc)
+{
+ char *policy_id;
+ xml_node_t *policy, *node;
+
+ policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
+ if (policy_id == NULL || strlen(policy_id) == 0) {
+ free(policy_id);
+ policy_id = strdup("default");
+ if (policy_id == NULL)
+ return NULL;
+ }
+ policy = read_policy_file(ctx, policy_id);
+ free(policy_id);
+ if (policy == NULL)
+ return NULL;
+
+ update_policy_update_uri(ctx, realm, policy);
+
+ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
+ if (node && use_dmacc) {
+ char *pw;
+ pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
+ if (pw == NULL ||
+ build_username_password(ctx, node, user, pw) == NULL) {
+ debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
+ "UsernamePassword");
+ free(pw);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+ free(pw);
+ }
+
+ return policy;
+}
+
+
+static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *session_id, int dmacc)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node;
+ xml_node_t *policy;
+ char buf[400];
+ const char *status;
+ char *identity;
+
+ identity = db_get_val(ctx, user, realm, "identity", dmacc);
+ if (identity == NULL || strlen(identity) == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "user not found in database for policy update",
+ NULL);
+ os_free(identity);
+ return build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred",
+ "Not found");
+ }
+ os_free(identity);
+
+ policy = build_policy(ctx, user, realm, dmacc);
+ if (!policy) {
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "No update available at this time", NULL);
+ }
+
+ db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
+ NULL);
+
+ status = "Update complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ xml_node_free(ctx->xml, policy);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
+ policy);
+ xml_node_free(ctx->xml, policy);
+
+ return spp_node;
+}
+
+
+static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
+ const char *urn, int *valid, char **ret_err)
+{
+ xml_node_t *child, *tnds, *mo;
+ const char *name;
+ char *mo_urn;
+ char *str;
+ char fname[200];
+
+ *valid = -1;
+ if (ret_err)
+ *ret_err = NULL;
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (strcmp(name, "moContainer") != 0)
+ continue;
+ mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
+ "moURN");
+ if (strcasecmp(urn, mo_urn) == 0) {
+ xml_node_get_attr_value_free(ctx->xml, mo_urn);
+ break;
+ }
+ xml_node_get_attr_value_free(ctx->xml, mo_urn);
+ }
+
+ if (child == NULL)
+ return NULL;
+
+ debug_print(ctx, 1, "moContainer text for %s", urn);
+ debug_dump_node(ctx, "moContainer", child);
+
+ str = xml_node_get_text(ctx->xml, child);
+ debug_print(ctx, 1, "moContainer payload: '%s'", str);
+ tnds = xml_node_from_buf(ctx->xml, str);
+ xml_node_get_text_free(ctx->xml, str);
+ if (tnds == NULL) {
+ debug_print(ctx, 1, "could not parse moContainer text");
+ return NULL;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
+ if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
+ *valid = 1;
+ else if (ret_err && *ret_err &&
+ os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
+ free(*ret_err);
+ debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
+ *ret_err = NULL;
+ *valid = 1;
+ } else
+ *valid = 0;
+
+ mo = tnds_to_mo(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (mo == NULL) {
+ debug_print(ctx, 1, "invalid moContainer for %s", urn);
+ }
+
+ return mo;
+}
+
+
+static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
+ const char *session_id, const char *urn)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node, *exec_node;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
+ const char *realm,
+ const char *session_id,
+ const char *redirect_uri,
+ const u8 *mac_addr)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *exec_node;
+ char uri[300], *val;
+
+ if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
+ SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
+ return NULL;
+ val = db_get_osu_config_val(ctx, realm, "signup_url");
+ if (val == NULL)
+ return NULL;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ snprintf(uri, sizeof(uri), "%s%s", val, session_id);
+ os_free(val);
+ xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
+ uri);
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
+}
+
+
+static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
+ const char *field)
+{
+ char *cmd;
+ struct get_db_field_data data;
+
+ cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
+ "field=%Q", realm, field);
+ if (cmd == NULL)
+ return NULL;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ memset(&data, 0, sizeof(data));
+ data.field = "value";
+ if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
+ {
+ debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
+ realm, sqlite3_errmsg(ctx->db));
+ sqlite3_free(cmd);
+ return NULL;
+ }
+ sqlite3_free(cmd);
+
+ debug_print(ctx, 1, "DB: return '%s'", data.value);
+ return data.value;
+}
+
+
+static xml_node_t * build_pps(struct hs20_svc *ctx,
+ const char *user, const char *realm,
+ const char *pw, const char *cert,
+ int machine_managed, const char *test,
+ const char *imsi, const char *dmacc_username,
+ const char *dmacc_password,
+ xml_node_t *policy_node)
+{
+ xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
+ xml_node_t *cred, *eap, *userpw;
+
+ pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "PerProviderSubscription");
+ if (!pps) {
+ xml_node_free(ctx->xml, policy_node);
+ return NULL;
+ }
+
+ add_text_node(ctx, pps, "UpdateIdentifier", "1");
+
+ c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
+
+ add_text_node(ctx, c, "CredentialPriority", "1");
+
+ if (imsi)
+ goto skip_aaa_trust_root;
+ aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
+ aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
+ add_text_node_conf(ctx, realm, aaa1, "CertURL",
+ "aaa_trust_root_cert_url");
+ if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, aaa1,
+ "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ }
+
+ if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
+ p = xml_node_create(ctx->xml, c, NULL, "Policy");
+ upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
+ add_text_node(ctx, upd, "UpdateInterval", "30");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+ add_text_node(ctx, upd, "Restriction", "Unrestricted");
+ add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
+ trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+ add_text_node_conf(ctx, realm, trust, "CertURL",
+ "policy_trust_root_cert_url");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "policy_trust_root_cert_fingerprint");
+ }
+skip_aaa_trust_root:
+
+ upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
+ add_text_node(ctx, upd, "UpdateInterval", "4294967295");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+ add_text_node(ctx, upd, "Restriction", "HomeSP");
+ add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
+ trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+ add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
+ if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ }
+
+ if (dmacc_username &&
+ !build_username_password(ctx, upd, dmacc_username,
+ dmacc_password)) {
+ xml_node_free(ctx->xml, pps);
+ xml_node_free(ctx->xml, policy_node);
+ return NULL;
+ }
+
+ if (policy_node)
+ xml_node_add_child(ctx->xml, c, policy_node);
+
+ homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
+ add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
+ add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
+
+ xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
+
+ cred = xml_node_create(ctx->xml, c, NULL, "Credential");
+ add_creation_date(ctx, cred);
+ if (imsi) {
+ xml_node_t *sim;
+ const char *type = "18"; /* default to EAP-SIM */
+
+ sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
+ add_text_node(ctx, sim, "IMSI", imsi);
+ if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
+ type = "23";
+ else if (ctx->eap_method &&
+ os_strcmp(ctx->eap_method, "AKA'") == 0)
+ type = "50";
+ add_text_node(ctx, sim, "EAPType", type);
+ } else if (cert) {
+ xml_node_t *dc;
+ dc = xml_node_create(ctx->xml, cred, NULL,
+ "DigitalCertificate");
+ add_text_node(ctx, dc, "CertificateType", "x509v3");
+ add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
+ } else {
+ userpw = build_username_password(ctx, cred, user, pw);
+ add_text_node(ctx, userpw, "MachineManaged",
+ machine_managed ? "TRUE" : "FALSE");
+ eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
+ add_text_node(ctx, eap, "EAPType", "21");
+ add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
+ }
+ add_text_node(ctx, cred, "Realm", realm);
+
+ return pps;
+}
+
+
+static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *user,
+ const char *realm,
+ int add_est_user)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *enroll, *exec_node;
+ char *val;
+ char password[11];
+ char *b64;
+
+ if (add_est_user && new_password(password, sizeof(password)) < 0)
+ return NULL;
+
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
+
+ enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
+ xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
+
+ val = db_get_osu_config_val(ctx, realm, "est_url");
+ xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
+ val ? val : "");
+ os_free(val);
+
+ if (!add_est_user)
+ return spp_node;
+
+ xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
+
+ b64 = base64_encode(password, strlen(password), NULL);
+ if (b64 == NULL) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+ xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
+ free(b64);
+
+ db_update_session_password(ctx, user, realm, session_id, password);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
+ const char *session_id,
+ int enrollment_done)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node = NULL;
+ xml_node_t *pps, *tnds;
+ char buf[400];
+ char *str;
+ char *user, *realm, *pw, *type, *mm, *test;
+ const char *status;
+ int cert = 0;
+ int machine_managed = 0;
+ char *fingerprint;
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
+
+ if (!user || !realm || !pw) {
+ debug_print(ctx, 1, "Could not find session info from DB for "
+ "the new subscription");
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+
+ mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
+ if (mm && atoi(mm))
+ machine_managed = 1;
+ free(mm);
+
+ type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
+ if (type && strcmp(type, "cert") == 0)
+ cert = 1;
+ free(type);
+
+ if (cert && !enrollment_done) {
+ xml_node_t *ret;
+ hs20_eventlog(ctx, user, realm, session_id,
+ "request client certificate enrollment", NULL);
+ ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
+ free(user);
+ free(realm);
+ free(pw);
+ return ret;
+ }
+
+ if (!cert && strlen(pw) == 0) {
+ machine_managed = 1;
+ free(pw);
+ pw = malloc(11);
+ if (pw == NULL || new_password(pw, 11) < 0) {
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+ }
+
+ status = "Provisioning complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
+ if (test)
+ debug_print(ctx, 1, "TEST: Requested special behavior: %s",
+ test);
+ pps = build_pps(ctx, user, realm, pw,
+ fingerprint ? fingerprint : NULL, machine_managed,
+ test, NULL, NULL, NULL, NULL);
+ free(fingerprint);
+ free(test);
+ if (!pps) {
+ xml_node_free(ctx->xml, spp_node);
+ free(user);
+ free(realm);
+ free(pw);
+ return NULL;
+ }
+
+ debug_print(ctx, 1, "Request DB subscription registration on success "
+ "notification");
+ if (machine_managed) {
+ db_update_session_password(ctx, user, realm, session_id, pw);
+ db_update_session_machine_managed(ctx, user, realm, session_id,
+ machine_managed);
+ }
+ db_add_session_pps(ctx, user, realm, session_id, pps);
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "new subscription", pps);
+ free(user);
+ free(pw);
+
+ tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
+ xml_node_free(ctx->xml, pps);
+ if (!tnds) {
+ xml_node_free(ctx->xml, spp_node);
+ free(realm);
+ return NULL;
+ }
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (str == NULL) {
+ xml_node_free(ctx->xml, spp_node);
+ free(realm);
+ return NULL;
+ }
+
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
+ free(str);
+ snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
+ free(realm);
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node;
+ xml_node_t *cred;
+ char buf[400];
+ char *status;
+ char *free_account, *pw;
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ if (free_account == NULL)
+ return NULL;
+ pw = db_get_val(ctx, free_account, realm, "password", 0);
+ if (pw == NULL) {
+ free(free_account);
+ return NULL;
+ }
+
+ cred = build_credential_pw(ctx, free_account, realm, pw, 1);
+ free(free_account);
+ free(pw);
+ if (!cred) {
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "free/public remediation", cred);
+ xml_node_free(ctx->xml, cred);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+
+ val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper == USER_REMEDIATION) {
+ return hs20_user_input_remediation(ctx, user, realm, dmacc,
+ session_id);
+ }
+
+ if (oper == FREE_REMEDIATION) {
+ return hs20_user_input_free_remediation(ctx, user, realm,
+ session_id);
+ }
+
+ if (oper == SUBSCRIPTION_REGISTRATION) {
+ return hs20_user_input_registration(ctx, session_id, 0);
+ }
+
+ debug_print(ctx, 1, "User session %s not in state for user input "
+ "completion", session_id);
+ return NULL;
+}
+
+
+static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
+ const char *session_id)
+{
+ char *user, *realm, *cert;
+ char *status;
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *cred;
+ char buf[400];
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ if (!user || !realm || !cert) {
+ debug_print(ctx, 1,
+ "Could not find session info from DB for certificate reenrollment");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ cred = build_credential_cert(ctx, user, realm, cert);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL) {
+ debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ free(user);
+ free(realm);
+ free(cert);
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ debug_print(ctx, 1, "Could not add update node");
+ xml_node_free(ctx->xml, spp_node);
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate reenrollment", cred);
+ xml_node_free(ctx->xml, cred);
+
+ free(user);
+ free(realm);
+ free(cert);
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper == SUBSCRIPTION_REGISTRATION)
+ return hs20_user_input_registration(ctx, session_id, 1);
+ if (oper == CERT_REENROLL)
+ return hs20_cert_reenroll_complete(ctx, session_id);
+
+ debug_print(ctx, 1, "User session %s not in state for certificate "
+ "enrollment completion", session_id);
+ return NULL;
+}
+
+
+static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ char *val;
+ enum hs20_session_operation oper;
+ xml_node_t *spp_node, *node;
+ char *status;
+ xml_namespace_t *ns;
+
+ val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ if (val == NULL) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ return NULL;
+ }
+ oper = atoi(val);
+ free(val);
+
+ if (oper != SUBSCRIPTION_REGISTRATION) {
+ debug_print(ctx, 1, "User session %s not in state for "
+ "enrollment failure", session_id);
+ return NULL;
+ }
+
+ status = "Error occurred";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL)
+ return NULL;
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ "Credentials cannot be provisioned at this time");
+ db_remove_session(ctx, user, realm, session_id);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node = NULL;
+ xml_node_t *pps, *tnds;
+ char buf[400];
+ char *str;
+ const char *status;
+ char dmacc_username[32];
+ char dmacc_password[32];
+ char *policy;
+ xml_node_t *policy_node = NULL;
+
+ if (!ctx->imsi) {
+ debug_print(ctx, 1, "IMSI not available for SIM provisioning");
+ return NULL;
+ }
+
+ if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
+ new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
+ debug_print(ctx, 1,
+ "Failed to generate DMAcc username/password");
+ return NULL;
+ }
+
+ status = "Provisioning complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (!spp_node)
+ return NULL;
+
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+ if (policy) {
+ policy_node = read_policy_file(ctx, policy);
+ os_free(policy);
+ if (!policy_node) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+ update_policy_update_uri(ctx, realm, policy_node);
+ node = get_node_uri(ctx->xml, policy_node,
+ "Policy/PolicyUpdate");
+ if (node)
+ build_username_password(ctx, node, dmacc_username,
+ dmacc_password);
+ }
+
+ pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
+ dmacc_username, dmacc_password, policy_node);
+ if (!pps) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ debug_print(ctx, 1,
+ "Request DB subscription registration on success notification");
+ if (!user || !user[0])
+ user = ctx->imsi;
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ SUBSCRIPTION_REGISTRATION, NULL);
+ db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
+ if (ctx->eap_method)
+ db_add_session_eap_method(ctx, session_id, ctx->eap_method);
+ if (ctx->id_hash)
+ db_add_session_id_hash(ctx, session_id, ctx->id_hash);
+ db_add_session_pps(ctx, user, realm, session_id, pps);
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "new subscription", pps);
+
+ tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
+ xml_node_free(ctx->xml, pps);
+ if (!tnds) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (!str) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
+ free(str);
+ snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
+
+ return spp_node;
+}
+
+
+static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
+ xml_node_t *node,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc)
+{
+ const char *req_reason;
+ char *redirect_uri = NULL;
+ char *req_reason_buf = NULL;
+ char str[200];
+ xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
+ xml_node_t *mo, *macaddr;
+ char *version;
+ int valid;
+ char *supp, *pos;
+ char *err;
+ u8 wifi_mac_addr[ETH_ALEN];
+
+ version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sppVersion");
+ if (version == NULL || strstr(version, "1.0") == NULL) {
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "SPP version not supported");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Unsupported sppVersion", ret);
+ xml_node_get_attr_value_free(ctx->xml, version);
+ return ret;
+ }
+ xml_node_get_attr_value_free(ctx->xml, version);
+
+ mo = get_node(ctx->xml, node, "supportedMOList");
+ if (mo == NULL) {
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No supportedMOList element", ret);
+ return ret;
+ }
+ supp = xml_node_get_text(ctx->xml, mo);
+ for (pos = supp; pos && *pos; pos++)
+ *pos = tolower(*pos);
+ if (supp == NULL ||
+ strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
+ strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
+ strstr(supp, URN_HS20_PPS) == NULL) {
+ xml_node_get_text_free(ctx->xml, supp);
+ ret = build_post_dev_data_response(
+ ctx, NULL, session_id, "Error occurred",
+ "One or more mandatory MOs not supported");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Unsupported MOs", ret);
+ return ret;
+ }
+ xml_node_get_text_free(ctx->xml, supp);
+
+ req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
+ "requestReason");
+ if (req_reason_buf == NULL) {
+ debug_print(ctx, 1, "No requestReason attribute");
+ return NULL;
+ }
+ req_reason = req_reason_buf;
+
+ redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
+
+ debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
+ req_reason, session_id, redirect_uri);
+ snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
+ req_reason);
+ hs20_eventlog(ctx, user, realm, session_id, str, NULL);
+
+ devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
+ if (devinfo == NULL) {
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No DevInfo moContainer in sppPostDevData",
+ ret);
+ os_free(err);
+ goto out;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received DevInfo MO", devinfo);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors in DevInfo MO",
+ err);
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ os_free(err);
+ goto out;
+ }
+ os_free(err);
+ if (user)
+ db_update_mo(ctx, user, realm, "devinfo", devinfo);
+
+ devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
+ if (devdetail == NULL) {
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "No DevDetail moContainer in sppPostDevData",
+ ret);
+ os_free(err);
+ goto out;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received DevDetail MO", devdetail);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors "
+ "in DevDetail MO", err);
+ ret = build_post_dev_data_response(ctx, NULL, session_id,
+ "Error occurred", "Other");
+ os_free(err);
+ goto out;
+ }
+ os_free(err);
+
+ os_memset(wifi_mac_addr, 0, ETH_ALEN);
+ macaddr = get_node(ctx->xml, devdetail,
+ "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
+ if (macaddr) {
+ char *addr, buf[50];
+
+ addr = xml_node_get_text(ctx->xml, macaddr);
+ if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
+ snprintf(buf, sizeof(buf), "DevDetail MAC address: "
+ MACSTR, MAC2STR(wifi_mac_addr));
+ hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
+ xml_node_get_text_free(ctx->xml, addr);
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "Could not extract MAC address from DevDetail",
+ NULL);
+ }
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "No MAC address in DevDetail", NULL);
+ }
+
+ if (user)
+ db_update_mo(ctx, user, realm, "devdetail", devdetail);
+
+ if (user)
+ mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
+ else {
+ mo = NULL;
+ err = NULL;
+ }
+ if (user && mo) {
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Received PPS MO", mo);
+ if (valid == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "OMA-DM DDF DTD validation errors "
+ "in PPS MO", err);
+ xml_node_get_attr_value_free(ctx->xml, redirect_uri);
+ os_free(err);
+ return build_post_dev_data_response(
+ ctx, NULL, session_id,
+ "Error occurred", "Other");
+ }
+ db_update_mo(ctx, user, realm, "pps", mo);
+ db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
+ xml_node_free(ctx->xml, mo);
+ }
+ os_free(err);
+
+ if (user && !mo) {
+ char *fetch;
+ int fetch_pps;
+
+ fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
+ fetch_pps = fetch ? atoi(fetch) : 0;
+ free(fetch);
+
+ if (fetch_pps) {
+ enum hs20_session_operation oper;
+ if (strcasecmp(req_reason, "Subscription remediation")
+ == 0)
+ oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
+ else if (strcasecmp(req_reason, "Policy update") == 0)
+ oper = CONTINUE_POLICY_UPDATE;
+ else
+ oper = NO_OPERATION;
+ if (db_add_session(ctx, user, realm, session_id, NULL,
+ NULL, oper, NULL) < 0)
+ goto out;
+
+ ret = spp_exec_upload_mo(ctx, session_id,
+ URN_HS20_PPS);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "request PPS MO upload",
+ ret);
+ goto out;
+ }
+ }
+
+ if (user && strcasecmp(req_reason, "MO upload") == 0) {
+ char *val = db_get_session_val(ctx, user, realm, session_id,
+ "operation");
+ enum hs20_session_operation oper;
+ if (!val) {
+ debug_print(ctx, 1, "No session %s found to continue",
+ session_id);
+ goto out;
+ }
+ oper = atoi(val);
+ free(val);
+ if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
+ req_reason = "Subscription remediation";
+ else if (oper == CONTINUE_POLICY_UPDATE)
+ req_reason = "Policy update";
+ else {
+ debug_print(ctx, 1,
+ "No pending operation in session %s",
+ session_id);
+ goto out;
+ }
+ }
+
+ if (strcasecmp(req_reason, "Subscription registration") == 0) {
+ ret = hs20_subscription_registration(ctx, realm, session_id,
+ redirect_uri,
+ wifi_mac_addr);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription registration response",
+ ret);
+ goto out;
+ }
+ if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
+ ret = hs20_subscription_remediation(ctx, user, realm,
+ session_id, dmacc,
+ redirect_uri);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription remediation response",
+ ret);
+ goto out;
+ }
+ if (user && strcasecmp(req_reason, "Policy update") == 0) {
+ ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "policy update response",
+ ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "User input completed") == 0) {
+ db_add_session_devinfo(ctx, session_id, devinfo);
+ db_add_session_devdetail(ctx, session_id, devdetail);
+ ret = hs20_user_input_complete(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "user input completed response", ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
+ ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate enrollment response", ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
+ ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate enrollment failed response",
+ ret);
+ goto out;
+ }
+
+ if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
+ ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription provisioning response",
+ ret);
+ goto out;
+ }
+
+ debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
+ req_reason, user);
+out:
+ xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
+ xml_node_get_attr_value_free(ctx->xml, redirect_uri);
+ if (devinfo)
+ xml_node_free(ctx->xml, devinfo);
+ if (devdetail)
+ xml_node_free(ctx->xml, devdetail);
+ return ret;
+}
+
+
+static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *status,
+ const char *error_code)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node;
+
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppExchangeComplete");
+
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
+
+ if (error_code) {
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ error_code);
+ }
+
+ return spp_node;
+}
+
+
+static int add_subscription(struct hs20_svc *ctx, const char *session_id)
+{
+ char *user, *realm, *pw, *pw_mm, *pps, *str;
+ char *osu_user, *osu_password, *eap_method;
+ char *policy = NULL;
+ char *sql;
+ int ret = -1;
+ char *free_account;
+ int free_acc;
+ char *type;
+ int cert = 0;
+ char *cert_pem, *fingerprint;
+ const char *method;
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
+ pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
+ "machine_managed");
+ pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
+ cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
+ fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
+ if (type && strcmp(type, "cert") == 0)
+ cert = 1;
+ free(type);
+ osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
+ osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
+ "osu_password");
+ eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
+ "eap_method");
+
+ if (!user || !realm || !pw) {
+ debug_print(ctx, 1, "Could not find session info from DB for "
+ "the new subscription");
+ goto out;
+ }
+
+ free_account = db_get_osu_config_val(ctx, realm, "free_account");
+ free_acc = free_account && strcmp(free_account, user) == 0;
+ free(free_account);
+
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+
+ debug_print(ctx, 1,
+ "New subscription: user='%s' realm='%s' free_acc=%d",
+ user, realm, free_acc);
+ debug_print(ctx, 1, "New subscription: pps='%s'", pps);
+
+ sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
+ "sessionid=%Q AND (user='' OR user IS NULL)",
+ user, realm, session_id);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update eventlog in "
+ "sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+
+ if (free_acc) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "completed shared free account registration",
+ NULL);
+ ret = 0;
+ goto out;
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
+
+ if (eap_method && eap_method[0])
+ method = eap_method;
+ else
+ method = cert ? "TLS" : "TTLS-MSCHAPV2";
+ sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
+ user, realm, cert ? 0 : 1,
+ method,
+ fingerprint ? fingerprint : "",
+ cert_pem ? cert_pem : "",
+ pw_mm && atoi(pw_mm) ? 1 : 0,
+ str ? str : "",
+ osu_user ? osu_user : "",
+ osu_password ? osu_password : "",
+ policy ? policy : "");
+ free(str);
+ if (sql == NULL)
+ goto out;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ sqlite3_free(sql);
+ goto out;
+ }
+ sqlite3_free(sql);
+
+ if (cert)
+ ret = 0;
+ else
+ ret = update_password(ctx, user, realm, pw, 0);
+ if (ret < 0) {
+ sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
+ user, realm);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
+ sqlite3_free(sql);
+ }
+ }
+
+ if (pps)
+ db_update_mo_str(ctx, user, realm, "pps", pps);
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
+ if (str) {
+ db_update_mo_str(ctx, user, realm, "devinfo", str);
+ free(str);
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
+ if (str) {
+ db_update_mo_str(ctx, user, realm, "devdetail", str);
+ free(str);
+ }
+
+ if (cert && user) {
+ const char *serialnum;
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mac_addr");
+
+ if (os_strncmp(user, "cert-", 5) == 0)
+ serialnum = user + 5;
+ else
+ serialnum = "";
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
+ str ? str : "", user, realm ? realm : "",
+ serialnum);
+ free(str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to add cert_enroll entry into sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mobile_identifier_hash");
+ if (str) {
+ sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
+ str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to delete pending sim_provisioning entry: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ os_free(str);
+ }
+
+ if (ret == 0) {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "completed subscription registration", NULL);
+ }
+
+out:
+ free(user);
+ free(realm);
+ free(pw);
+ free(pw_mm);
+ free(pps);
+ free(cert_pem);
+ free(fingerprint);
+ free(osu_user);
+ free(osu_password);
+ free(eap_method);
+ os_free(policy);
+ return ret;
+}
+
+
+static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
+ xml_node_t *node,
+ const char *user,
+ const char *realm,
+ const char *session_id,
+ int dmacc)
+{
+ char *status;
+ xml_node_t *ret;
+ char *val;
+ enum hs20_session_operation oper;
+
+ status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sppStatus");
+ if (status == NULL) {
+ debug_print(ctx, 1, "No sppStatus attribute");
+ return NULL;
+ }
+
+ debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
+ status, session_id);
+
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
+ if (!val) {
+ debug_print(ctx, 1,
+ "No session active for sessionID: %s",
+ session_id);
+ oper = NO_OPERATION;
+ } else
+ oper = atoi(val);
+
+ if (strcasecmp(status, "OK") == 0) {
+ char *new_pw = NULL;
+
+ xml_node_get_attr_value_free(ctx->xml, status);
+
+ if (oper == USER_REMEDIATION) {
+ new_pw = db_get_session_val(ctx, user, realm,
+ session_id, "password");
+ if (new_pw == NULL || strlen(new_pw) == 0) {
+ free(new_pw);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "No password "
+ "had been assigned for "
+ "session", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ oper = UPDATE_PASSWORD;
+ }
+ if (oper == UPDATE_PASSWORD) {
+ if (!new_pw) {
+ new_pw = db_get_session_val(ctx, user, realm,
+ session_id,
+ "password");
+ if (!new_pw) {
+ db_remove_session(ctx, user, realm,
+ session_id);
+ return NULL;
+ }
+ }
+ debug_print(ctx, 1, "Update user '%s' password in DB",
+ user);
+ if (update_password(ctx, user, realm, new_pw, dmacc) <
+ 0) {
+ debug_print(ctx, 1, "Failed to update user "
+ "'%s' password in DB", user);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "Failed to "
+ "update database", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ hs20_eventlog(ctx, user, realm,
+ session_id, "Updated user password "
+ "in database", NULL);
+ }
+ if (oper == CLEAR_REMEDIATION) {
+ debug_print(ctx, 1,
+ "Clear remediation requirement for user '%s' in DB",
+ user);
+ if (clear_remediation(ctx, user, realm, dmacc) < 0) {
+ debug_print(ctx, 1,
+ "Failed to clear remediation requirement for user '%s' in DB",
+ user);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update database",
+ ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ hs20_eventlog(ctx, user, realm,
+ session_id,
+ "Cleared remediation requirement in database",
+ NULL);
+ }
+ if (oper == SUBSCRIPTION_REGISTRATION) {
+ if (add_subscription(ctx, session_id) < 0) {
+ debug_print(ctx, 1, "Failed to add "
+ "subscription into DB");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id, "Failed to "
+ "update database", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ }
+ if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
+ char *val;
+ val = db_get_val(ctx, user, realm, "remediation",
+ dmacc);
+ if (val && strcmp(val, "policy") == 0)
+ db_update_val(ctx, user, realm, "remediation",
+ "", dmacc);
+ free(val);
+ }
+ if (oper == POLICY_UPDATE)
+ db_update_val(ctx, user, realm, "polupd_done", "1",
+ dmacc);
+ if (oper == CERT_REENROLL) {
+ char *new_user;
+ char event[200];
+
+ new_user = db_get_session_val(ctx, NULL, NULL,
+ session_id, "user");
+ if (!new_user) {
+ debug_print(ctx, 1,
+ "Failed to find new user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to find new user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ return ret;
+ }
+
+ debug_print(ctx, 1,
+ "Update certificate user entry to use the new serial number (old=%s new=%s)",
+ user, new_user);
+ os_snprintf(event, sizeof(event), "renamed user to: %s",
+ new_user);
+ hs20_eventlog(ctx, user, realm, session_id, event,
+ NULL);
+
+ if (db_update_val(ctx, user, realm, "identity",
+ new_user, 0) < 0 ||
+ db_update_val(ctx, new_user, realm, "remediation",
+ "", 0) < 0) {
+ debug_print(ctx, 1,
+ "Failed to update user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ os_free(new_user);
+ return ret;
+ }
+
+ os_free(new_user);
+ }
+ ret = build_spp_exchange_complete(
+ ctx, session_id,
+ "Exchange complete, release TLS connection", NULL);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "Exchange completed", ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ return ret;
+ }
+
+ ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
+ db_remove_session(ctx, user, realm, session_id);
+ xml_node_get_attr_value_free(ctx->xml, status);
+ return ret;
+}
+
+
+#define SPP_SESSION_ID_LEN 16
+
+static char * gen_spp_session_id(void)
+{
+ FILE *f;
+ int i;
+ char *session;
+
+ session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
+ if (session == NULL)
+ return NULL;
+
+ f = fopen("/dev/urandom", "r");
+ if (f == NULL) {
+ os_free(session);
+ return NULL;
+ }
+ for (i = 0; i < SPP_SESSION_ID_LEN; i++)
+ os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
+
+ fclose(f);
+ return session;
+}
+
+xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
+ const char *auth_user,
+ const char *auth_realm, int dmacc)
+{
+ xml_node_t *ret = NULL;
+ char *session_id;
+ const char *op_name;
+ char *xml_err;
+ char fname[200];
+
+ debug_dump_node(ctx, "received request", node);
+
+ if (!dmacc && auth_user && auth_realm) {
+ char *real;
+ real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
+ if (!real) {
+ real = db_get_val(ctx, auth_user, auth_realm,
+ "identity", 1);
+ if (real)
+ dmacc = 1;
+ }
+ os_free(real);
+ }
+
+ snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
+ if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
+ /*
+ * We may not be able to extract the sessionID from invalid
+ * input, but well, we can try.
+ */
+ session_id = xml_node_get_attr_value_ns(ctx->xml, node,
+ SPP_NS_URI,
+ "sessionID");
+ debug_print(ctx, 1,
+ "SPP message failed validation, xsd file: %s xml-error: %s",
+ fname, xml_err);
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "SPP message failed validation", node);
+ hs20_eventlog(ctx, auth_user, auth_realm, session_id,
+ "Validation errors", xml_err);
+ os_free(xml_err);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppValidationError");
+ return ret;
+ }
+
+ session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
+ "sessionID");
+ if (session_id) {
+ char *tmp;
+ debug_print(ctx, 1, "Received sessionID %s", session_id);
+ tmp = os_strdup(session_id);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+ if (tmp == NULL)
+ return NULL;
+ session_id = tmp;
+ } else {
+ session_id = gen_spp_session_id();
+ if (session_id == NULL) {
+ debug_print(ctx, 1, "Failed to generate sessionID");
+ return NULL;
+ }
+ debug_print(ctx, 1, "Generated sessionID %s", session_id);
+ }
+
+ op_name = xml_node_get_localname(ctx->xml, node);
+ if (op_name == NULL) {
+ debug_print(ctx, 1, "Could not get op_name");
+ return NULL;
+ }
+
+ if (strcmp(op_name, "sppPostDevData") == 0) {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "sppPostDevData received and validated",
+ node);
+ ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
+ session_id, dmacc);
+ } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "sppUpdateResponse received and validated",
+ node);
+ ret = hs20_spp_update_response(ctx, node, auth_user,
+ auth_realm, session_id, dmacc);
+ } else {
+ hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
+ "Unsupported SPP message received and "
+ "validated", node);
+ debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppUnknownCommandError");
+ }
+ os_free(session_id);
+
+ if (ret == NULL) {
+ /* TODO: what to return here? */
+ ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
+ "SppInternalError");
+ }
+
+ return ret;
+}
+
+
+int hs20_spp_server_init(struct hs20_svc *ctx)
+{
+ char fname[200];
+ ctx->db = NULL;
+ snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
+ if (sqlite3_open(fname, &ctx->db)) {
+ printf("Failed to open sqlite database: %s\n",
+ sqlite3_errmsg(ctx->db));
+ sqlite3_close(ctx->db);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hs20_spp_server_deinit(struct hs20_svc *ctx)
+{
+ sqlite3_close(ctx->db);
+ ctx->db = NULL;
+}
diff --git a/contrib/wpa/hs20/server/spp_server.h b/contrib/wpa/hs20/server/spp_server.h
new file mode 100644
index 000000000000..421974c607b8
--- /dev/null
+++ b/contrib/wpa/hs20/server/spp_server.h
@@ -0,0 +1,36 @@
+/*
+ * Hotspot 2.0 SPP server
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SPP_SERVER_H
+#define SPP_SERVER_H
+
+struct hs20_svc {
+ const void *ctx;
+ struct xml_node_ctx *xml;
+ char *root_dir;
+ FILE *debug_log;
+ sqlite3 *db;
+ const char *addr;
+ const char *test;
+ const char *imsi;
+ const char *eap_method;
+ const char *id_hash;
+};
+
+
+void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node);
+
+xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
+ const char *auth_user,
+ const char *auth_realm, int dmacc);
+int hs20_spp_server_init(struct hs20_svc *ctx);
+void hs20_spp_server_deinit(struct hs20_svc *ctx);
+
+#endif /* SPP_SERVER_H */
diff --git a/contrib/wpa/hs20/server/sql-example.txt b/contrib/wpa/hs20/server/sql-example.txt
new file mode 100644
index 000000000000..20dcf2f5c688
--- /dev/null
+++ b/contrib/wpa/hs20/server/sql-example.txt
@@ -0,0 +1,17 @@
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id=');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id=');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id=');
+
+
+INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1);
+
+INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS');
diff --git a/contrib/wpa/hs20/server/sql.txt b/contrib/wpa/hs20/server/sql.txt
new file mode 100644
index 000000000000..2cc6edea4063
--- /dev/null
+++ b/contrib/wpa/hs20/server/sql.txt
@@ -0,0 +1,108 @@
+CREATE TABLE eventlog(
+ user TEXT,
+ realm TEXT,
+ sessionid TEXT COLLATE NOCASE,
+ timestamp TEXT,
+ notes TEXT,
+ dump TEXT,
+ addr TEXT
+);
+
+CREATE TABLE sessions(
+ timestamp TEXT,
+ id TEXT COLLATE NOCASE,
+ user TEXT,
+ realm TEXT,
+ password TEXT,
+ machine_managed BOOLEAN,
+ operation INTEGER,
+ type TEXT,
+ pps TEXT,
+ redirect_uri TEXT,
+ devinfo TEXT,
+ devdetail TEXT,
+ cert TEXT,
+ cert_pem TEXT,
+ mac_addr TEXT,
+ osu_user TEXT,
+ osu_password TEXT,
+ eap_method TEXT,
+ mobile_identifier_hash TEXT,
+ test TEXT
+);
+
+CREATE index sessions_id_index ON sessions(id);
+
+CREATE TABLE osu_config(
+ realm TEXT,
+ field TEXT,
+ value TEXT
+);
+
+CREATE TABLE users(
+ identity TEXT PRIMARY KEY,
+ methods TEXT,
+ password TEXT,
+ machine_managed BOOLEAN,
+ remediation TEXT,
+ phase2 INTEGER,
+ realm TEXT,
+ policy TEXT,
+ devinfo TEXT,
+ devdetail TEXT,
+ pps TEXT,
+ fetch_pps INTEGER,
+ osu_user TEXT,
+ osu_password TEXT,
+ shared INTEGER,
+ cert TEXT,
+ cert_pem TEXT,
+ t_c_timestamp INTEGER,
+ mac_addr TEXT,
+ last_msk TEXT,
+ polupd_done TEXT,
+ subrem TEXT
+);
+
+CREATE TABLE wildcards(
+ identity TEXT PRIMARY KEY,
+ methods TEXT
+);
+
+CREATE TABLE authlog(
+ timestamp TEXT,
+ session TEXT,
+ nas_ip TEXT,
+ username TEXT,
+ note TEXT
+);
+
+CREATE TABLE pending_tc(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT
+);
+
+CREATE TABLE current_sessions(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT,
+ start_time TEXT,
+ nas TEXT,
+ hs20_t_c_filtering BOOLEAN,
+ waiting_coa_ack BOOLEAN,
+ coa_ack_received BOOLEAN
+);
+
+CREATE TABLE cert_enroll(
+ mac_addr TEXT PRIMARY KEY,
+ user TEXT,
+ realm TEXT,
+ serialnum TEXT
+);
+
+CREATE TABLE sim_provisioning(
+ mobile_identifier_hash TEXT PRIMARY KEY,
+ imsi TEXT,
+ mac_addr TEXT,
+ eap_method TEXT,
+ timestamp TEXT
+);
diff --git a/contrib/wpa/hs20/server/www/add-free.php b/contrib/wpa/hs20/server/www/add-free.php
new file mode 100644
index 000000000000..1efc65563274
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/add-free.php
@@ -0,0 +1,50 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_POST["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
+else
+ die("Missing session id");
+if (strlen($id) < 32)
+ die("Invalid session id");
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+$realm = $row['realm'];
+
+$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
+if (!$row || strlen($row['value']) == 0) {
+ die("Free account disabled");
+}
+
+$user = $row['value'];
+
+$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
+if (!$row)
+ die("Free account not found");
+
+$pw = $row['password'];
+
+if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for a new PPS MO')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/contrib/wpa/hs20/server/www/add-mo.php b/contrib/wpa/hs20/server/www/add-mo.php
new file mode 100644
index 000000000000..a3b4513531f8
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/add-mo.php
@@ -0,0 +1,56 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_POST["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
+else
+ die("Missing session id");
+
+$user = $_POST["user"];
+$pw = $_POST["password"];
+if (strlen($id) < 32 || !isset($user) || !isset($pw)) {
+ die("Invalid POST data");
+}
+
+if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) {
+ echo "<html><body><p><red>Invalid username</red></p>\n";
+ echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
+ echo "</body></html>\n";
+ exit;
+}
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+$realm = $row['realm'];
+
+$userrow = $db->query("SELECT identity FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
+if ($userrow) {
+ echo "<html><body><p><red>Selected username is not available</red></p>\n";
+ echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
+ echo "</body></html>\n";
+ exit;
+}
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+
+if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', type='password' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for a new PPS MO')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/contrib/wpa/hs20/server/www/cert-enroll.php b/contrib/wpa/hs20/server/www/cert-enroll.php
new file mode 100644
index 000000000000..f023ca5a5b03
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/cert-enroll.php
@@ -0,0 +1,39 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_GET["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
+else
+ die("Missing session id");
+if (strlen($id) < 32)
+ die("Invalid session id");
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+$realm = $row['realm'];
+
+$user = sha1(mt_rand());
+
+if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for client certificate enrollment')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/contrib/wpa/hs20/server/www/config.php b/contrib/wpa/hs20/server/www/config.php
new file mode 100644
index 000000000000..4272b102a88c
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/config.php
@@ -0,0 +1,7 @@
+<?php
+$osu_root = "/home/user/hs20-server";
+$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
+$t_c_file = "$osu_root/terms-and-conditions";
+$t_c_timestamp = 123456789;
+$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
+?>
diff --git a/contrib/wpa/hs20/server/www/est.php b/contrib/wpa/hs20/server/www/est.php
new file mode 100644
index 000000000000..b7fb260d56c4
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/est.php
@@ -0,0 +1,232 @@
+<?php
+
+require('config.php');
+
+$params = explode("/", $_SERVER["PATH_INFO"], 3);
+$realm = $params[1];
+$cmd = $params[2];
+$method = $_SERVER["REQUEST_METHOD"];
+
+unset($user);
+unset($rowid);
+
+$db = new PDO($osu_db);
+if (!$db) {
+ error_log("EST: Could not access database");
+ die("Could not access database");
+}
+
+if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
+ $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
+ 'uri'=>1, 'response'=>1);
+ $data = array();
+ $keys = implode('|', array_keys($needed));
+ preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
+ $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
+ foreach ($matches as $m) {
+ $data[$m[1]] = $m[3] ? $m[3] : $m[4];
+ unset($needed[$m[1]]);
+ }
+ if ($needed) {
+ error_log("EST: Missing auth parameter");
+ die('Authentication failed');
+ }
+ $user = $data['username'];
+ if (strlen($user) < 1) {
+ error_log("EST: Empty username");
+ die('Authentication failed');
+ }
+
+ $sql = "SELECT rowid,password,operation FROM sessions " .
+ "WHERE user='$user' AND realm='$realm'";
+ $q = $db->query($sql);
+ if (!$q) {
+ error_log("EST: Session not found for user=$user realm=$realm");
+ die("Session not found");
+ }
+ $row = $q->fetch();
+ if (!$row) {
+ error_log("EST: Session fetch failed for user=$user realm=$realm");
+ die('Session not found');
+ }
+ $rowid = $row['rowid'];
+
+ $oper = $row['operation'];
+ if ($oper != '5') {
+ error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
+ die("Session not found");
+ }
+ $pw = $row['password'];
+ if (strlen($pw) < 1) {
+ error_log("EST: Empty password for user=$user realm=$realm");
+ die('Authentication failed');
+ }
+
+ $A1 = md5($user . ':' . $realm . ':' . $pw);
+ $A2 = md5($method . ':' . $data['uri']);
+ $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
+ $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
+ if ($data['response'] != $resp) {
+ error_log("EST: Incorrect authentication response for user=$user realm=$realm");
+ die('Authentication failed');
+ }
+} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
+ $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
+ isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
+ $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
+ $sql = "SELECT rowid,password,operation FROM sessions " .
+ "WHERE user='$user' AND realm='$realm'";
+ $q = $db->query($sql);
+ if (!$q) {
+ error_log("EST: Session not found for user=$user realm=$realm");
+ die("Session not found");
+ }
+ $row = $q->fetch();
+ if (!$row) {
+ error_log("EST: Session fetch failed for user=$user realm=$realm");
+ die('Session not found');
+ }
+ $rowid = $row['rowid'];
+
+ $oper = $row['operation'];
+ if ($oper != '10') {
+ error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
+ die("Session not found");
+ }
+}
+
+
+if ($method == "GET" && $cmd == "cacerts") {
+ $fname = "$osu_root/est/$realm-cacerts.pkcs7";
+ if (!file_exists($fname)) {
+ error_log("EST: cacerts - unknown realm $realm");
+ die("Unknown realm");
+ }
+
+ header("Content-Transfer-Encoding: base64");
+ header("Content-Type: application/pkcs7-mime");
+
+ $data = file_get_contents($fname);
+ echo wordwrap(base64_encode($data), 72, "\n", true);
+ echo "\n";
+ error_log("EST: cacerts");
+} else if ($method == "GET" && $cmd == "csrattrs") {
+ header("Content-Transfer-Encoding: base64");
+ header("Content-Type: application/csrattrs");
+ readfile("$osu_root/est/est-attrs.b64");
+ error_log("EST: csrattrs");
+} else if ($method == "POST" &&
+ ($cmd == "simpleenroll" || $cmd == "simplereenroll")) {
+ $reenroll = $cmd == "simplereenroll";
+ if (!$reenroll && (!isset($user) || strlen($user) == 0)) {
+ header('HTTP/1.1 401 Unauthorized');
+ header('WWW-Authenticate: Digest realm="'.$realm.
+ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
+ error_log("EST: simpleenroll - require authentication");
+ die('Authentication required');
+ }
+ if ($reenroll &&
+ (!isset($user) ||
+ !isset($_SERVER["SSL_CLIENT_VERIFY"]) ||
+ $_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) {
+ header('HTTP/1.1 403 Forbidden');
+ error_log("EST: simplereenroll - require certificate authentication");
+ die('Authentication required');
+ }
+ if (!isset($_SERVER["CONTENT_TYPE"])) {
+ error_log("EST: simpleenroll without Content-Type");
+ die("Missing Content-Type");
+ }
+ if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) {
+ error_log("EST: simpleenroll - unexpected Content-Type: " .
+ $_SERVER["CONTENT_TYPE"]);
+ die("Unexpected Content-Type");
+ }
+
+ $data = file_get_contents("php://input");
+ error_log("EST: simpleenroll - POST data from php://input: " . $data);
+ $req = base64_decode($data);
+ if ($req == FALSE) {
+ error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data");
+ die("Invalid base64-encoded PKCS#10 data");
+ }
+ $cadir = "$osu_root/est";
+ $reqfile = "$cadir/tmp/cert-req.pkcs10";
+ $f = fopen($reqfile, "wb");
+ fwrite($f, $req);
+ fclose($f);
+
+ $req_pem = "$reqfile.pem";
+ if (file_exists($req_pem))
+ unlink($req_pem);
+ exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM");
+ if (!file_exists($req_pem)) {
+ error_log("EST: simpleenroll - Failed to parse certificate request");
+ die("Failed to parse certificate request");
+ }
+
+ /* FIX: validate request and add HS 2.0 extensions to cert */
+ $cert_pem = "$cadir/tmp/req-signed.pem";
+ if (file_exists($cert_pem))
+ unlink($cert_pem);
+ exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text");
+ if (!file_exists($cert_pem)) {
+ error_log("EST: simpleenroll - Failed to sign certificate");
+ die("Failed to sign certificate");
+ }
+
+ $cert = file_get_contents($cert_pem);
+ $handle = popen("openssl x509 -in $cert_pem -serial -noout", "r");
+ $serial = fread($handle, 200);
+ pclose($handle);
+ $pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m";
+ preg_match($pattern, $serial, $matches);
+ if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) {
+ error_log("EST: simpleenroll - Could not get serial number");
+ die("Could not get serial number");
+ }
+ $sn = str_replace(":", "", strtoupper($matches['snhex']));
+
+ $user = "cert-$sn";
+ error_log("EST: user = $user");
+
+ $cert_der = "$cadir/tmp/req-signed.der";
+ if (file_exists($cert_der))
+ unlink($cert_der);
+ exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER");
+ if (!file_exists($cert_der)) {
+ error_log("EST: simpleenroll - Failed to convert certificate");
+ die("Failed to convert certificate");
+ }
+ $der = file_get_contents($cert_der);
+ $fingerprint = hash("sha256", $der);
+ error_log("EST: sha256(DER cert): $fingerprint");
+
+ $pkcs7 = "$cadir/tmp/est-client.pkcs7";
+ if (file_exists($pkcs7))
+ unlink($pkcs7);
+ exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER");
+ if (!file_exists($pkcs7)) {
+ error_log("EST: simpleenroll - Failed to prepare PKCS#7 file");
+ die("Failed to prepare PKCS#7 file");
+ }
+
+ if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) {
+ error_log("EST: simpleenroll - Failed to update session database");
+ die("Failed to update session database");
+ }
+
+ header("Content-Transfer-Encoding: base64");
+ header("Content-Type: application/pkcs7-mime");
+
+ $data = file_get_contents($pkcs7);
+ $resp = wordwrap(base64_encode($data), 72, "\n", true);
+ echo $resp . "\n";
+ error_log("EST: simpleenroll - PKCS#7 response: " . $resp);
+} else {
+ header("HTTP/1.0 404 Not Found");
+ error_log("EST: Unexpected method or path");
+ die("Unexpected method or path");
+}
+
+?>
diff --git a/contrib/wpa/hs20/server/www/free-remediation.php b/contrib/wpa/hs20/server/www/free-remediation.php
new file mode 100644
index 000000000000..5648b30e8d6b
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/free-remediation.php
@@ -0,0 +1,19 @@
+<html>
+<head>
+<title>Hotspot 2.0 - public and free hotspot - remediation</title>
+</head>
+<body>
+
+<h3>Hotspot 2.0 - public and free hotspot</h3>
+
+<p>Terms and conditions have changed. You need to accept the new terms
+to continue using this network.</p>
+
+<p>Terms and conditions..</p>
+
+<?php
+echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Accept</a><br>\n";
+?>
+
+</body>
+</html>
diff --git a/contrib/wpa/hs20/server/www/free.php b/contrib/wpa/hs20/server/www/free.php
new file mode 100644
index 000000000000..8195069ed8ff
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/free.php
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Hotspot 2.0 - public and free hotspot</title>
+</head>
+<body>
+
+<?php
+
+$id = $_GET["session_id"];
+
+echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n";
+
+echo "<form action=\"add-free.php\" method=\"POST\">\n";
+echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
+
+?>
+
+<p>Terms and conditions..</p>
+<input type="submit" value="Accept">
+</form>
+
+</body>
+</html>
diff --git a/contrib/wpa/hs20/server/www/redirect.php b/contrib/wpa/hs20/server/www/redirect.php
new file mode 100644
index 000000000000..8fc9cd644273
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/redirect.php
@@ -0,0 +1,32 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_GET["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
+else
+ $id = 0;
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$uri = $row['redirect_uri'];
+
+header("Location: $uri", true, 302);
+
+$user = $row['user'];
+$realm = $row['realm'];
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'redirected after user input')");
+
+?>
diff --git a/contrib/wpa/hs20/server/www/remediation-pw.php b/contrib/wpa/hs20/server/www/remediation-pw.php
new file mode 100644
index 000000000000..76fdccbdf9f7
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/remediation-pw.php
@@ -0,0 +1,41 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_POST["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
+else
+ die("Missing session id");
+
+$pw = $_POST["password"];
+if (strlen($id) < 32 || !isset($pw)) {
+ die("Invalid POST data");
+}
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+$user = $row['user'];
+$realm = $row['realm'];
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+
+if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for subscription remediation')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/contrib/wpa/hs20/server/www/remediation.php b/contrib/wpa/hs20/server/www/remediation.php
new file mode 100644
index 000000000000..3628065ac225
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/remediation.php
@@ -0,0 +1,55 @@
+<html>
+<head>
+<title>Hotspot 2.0 subscription remediation</title>
+</head>
+<body>
+
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_GET["session_id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
+else
+ $id = 0;
+echo "SessionID: " . $id . "<br>\n";
+
+$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$username = $row['user'];
+echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
+
+$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
+if ($user == false) {
+ die("User not found");
+}
+
+echo "<hr><br>\n";
+
+$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
+
+if ($cert) {
+ echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+} else if ($user['machine_managed'] == "1") {
+ echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+ echo "This will provide a new machine-generated password.<br>\n";
+} else {
+ echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
+ echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
+ echo "New password: <input type=\"password\" name=\"password\"><br>\n";
+ echo "<input type=\"submit\" value=\"Change password\">\n";
+ echo "</form>\n";
+}
+
+?>
+
+</body>
+</html>
diff --git a/contrib/wpa/hs20/server/www/signup.php b/contrib/wpa/hs20/server/www/signup.php
new file mode 100644
index 000000000000..80a9d403e8fc
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/signup.php
@@ -0,0 +1,59 @@
+<html>
+<head>
+<title>Hotspot 2.0 signup</title>
+</head>
+<body>
+
+<?php
+
+$id = $_GET["session_id"];
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found for id: $id");
+}
+$realm = $row['realm'];
+$test = $row['test'];
+
+if (strlen($test) > 0) {
+ echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
+}
+
+echo "<h3>Sign up for a subscription - $realm</h3>\n";
+
+echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
+
+echo "<h4>Option 1 - shared free access credential</h4>\n";
+
+$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
+if ($row && strlen($row['value']) > 0) {
+ echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
+}
+
+echo "<h4>Option 2 - username/password credential</h4>\n";
+
+echo "<form action=\"add-mo.php\" method=\"POST\">\n";
+echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
+?>
+Select a username and password. Leave password empty to get automatically
+generated and machine managed password.<br>
+Username: <input type="text" name="user"><br>
+Password: <input type="password" name="password"><br>
+<input type="submit" value="Complete subscription registration">
+</form>
+
+<?php
+echo "<h4>Option 3 - client certificate credential</h4>\n";
+
+echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
+?>
+
+</body>
+</html>
diff --git a/contrib/wpa/hs20/server/www/spp.php b/contrib/wpa/hs20/server/www/spp.php
new file mode 100644
index 000000000000..c56d3d69e0ed
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/spp.php
@@ -0,0 +1,168 @@
+<?php
+
+require('config.php');
+
+if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) {
+ error_log("spp.php - Unexpected Content-Type " . $_SERVER["CONTENT_TYPE"]);
+ die("Unexpected Content-Type");
+}
+
+if ($_SERVER["REQUEST_METHOD"] != "POST") {
+ error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]);
+ die("Unexpected method");
+}
+
+if (isset($_GET["realm"])) {
+ $realm = $_GET["realm"];
+ $realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm);
+} else {
+ error_log("spp.php - Realm not specified");
+ die("Realm not specified");
+}
+
+if (isset($_GET["test"]))
+ $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
+else
+ $test = "";
+
+unset($user);
+putenv("HS20CERT");
+
+if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
+ $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
+ 'uri'=>1, 'response'=>1);
+ $data = array();
+ $keys = implode('|', array_keys($needed));
+ preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
+ $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
+ foreach ($matches as $m) {
+ $data[$m[1]] = $m[3] ? $m[3] : $m[4];
+ unset($needed[$m[1]]);
+ }
+ if ($needed) {
+ error_log("spp.php - Authentication failed - missing: " . print_r($needed));
+ die('Authentication failed');
+ }
+ $user = $data['username'];
+ if (strlen($user) < 1) {
+ error_log("spp.php - Authentication failed - empty username");
+ die('Authentication failed');
+ }
+
+
+ $db = new PDO($osu_db);
+ if (!$db) {
+ error_log("spp.php - Could not access database");
+ die("Could not access database");
+ }
+ $row = $db->query("SELECT password FROM users " .
+ "WHERE identity='$user' AND realm='$realm'")->fetch();
+ if (!$row) {
+ $row = $db->query("SELECT osu_password FROM users " .
+ "WHERE osu_user='$user' AND realm='$realm'")->fetch();
+ $pw = $row['osu_password'];
+ } else
+ $pw = $row['password'];
+ if (!$row) {
+ error_log("spp.php - Authentication failed - user '$user' not found");
+ die('Authentication failed');
+ }
+ if (strlen($pw) < 1) {
+ error_log("spp.php - Authentication failed - empty password");
+ die('Authentication failed');
+ }
+
+ $A1 = md5($user . ':' . $realm . ':' . $pw);
+ $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
+ $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
+ $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
+ if ($data['response'] != $resp) {
+ error_log("Authentication failure - response mismatch");
+ die('Authentication failed');
+ }
+} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
+ $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
+ isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
+ $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
+ putenv("HS20CERT=yes");
+} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) {
+ $id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"];
+ $id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash);
+
+ $db = new PDO($osu_db);
+ if (!$db) {
+ error_log("spp.php - Could not access database");
+ die("Could not access database");
+ }
+
+ $row = $db->query("SELECT * FROM sim_provisioning " .
+ "WHERE mobile_identifier_hash='$id_hash'")->fetch();
+ if (!$row) {
+ error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found");
+ die('SIM provisioning failed - mobile_identifier_hash not found');
+ }
+
+ $imsi = $row['imsi'];
+ $mac_addr = $row['mac_addr'];
+ $eap_method = $row['eap_method'];
+
+ $row = $db->query("SELECT COUNT(*) FROM osu_config " .
+ "WHERE realm='$realm'")->fetch();
+ if (!$row || intval($row[0]) < 1) {
+ error_log("spp.php - SIM provisioning failed - realm $realm not found");
+ die('SIM provisioning failed');
+ }
+
+ error_log("spp.php - SIM provisioning for IMSI $imsi");
+ putenv("HS20SIMPROV=yes");
+ putenv("HS20IMSI=$imsi");
+ putenv("HS20MACADDR=$mac_addr");
+ putenv("HS20EAPMETHOD=$eap_method");
+ putenv("HS20IDHASH=$id_hash");
+} else if (!isset($_SERVER["PATH_INFO"]) ||
+ $_SERVER["PATH_INFO"] != "/signup") {
+ header('HTTP/1.1 401 Unauthorized');
+ header('WWW-Authenticate: Digest realm="'.$realm.
+ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
+ error_log("spp.php - Authentication required (not signup)");
+ die('Authentication required (not signup)');
+}
+
+
+if (isset($user) && strlen($user) > 0)
+ putenv("HS20USER=$user");
+else
+ putenv("HS20USER");
+
+putenv("HS20REALM=$realm");
+$postdata = file_get_contents("php://input");
+putenv("HS20POST=$postdata");
+$addr = $_SERVER["REMOTE_ADDR"];
+putenv("HS20ADDR=$addr");
+putenv("HS20TEST=$test");
+
+$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
+
+if ($ret == 2) {
+ if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
+ header('HTTP/1.1 401 Unauthorized');
+ header('WWW-Authenticate: Digest realm="'.$realm.
+ '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
+ error_log("spp.php - Authentication required (ret 2)");
+ die('Authentication required');
+ } else {
+ error_log("spp.php - Unexpected authentication error");
+ die("Unexpected authentication error");
+ }
+}
+if ($ret != 0) {
+ error_log("spp.php - Failed to process SPP request");
+ die("Failed to process SPP request");
+}
+//error_log("spp.php: Response: " . implode($output));
+
+header("Content-Type: application/soap+xml");
+
+echo implode($output);
+
+?>
diff --git a/contrib/wpa/hs20/server/www/terms.php b/contrib/wpa/hs20/server/www/terms.php
new file mode 100644
index 000000000000..acba23ef1ad7
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/terms.php
@@ -0,0 +1,87 @@
+<?php
+
+require('config.php');
+
+function print_header()
+{
+ echo "<html>\n";
+ echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n";
+ echo "<body>\n";
+}
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (!isset($_GET["addr"])) {
+ die("Missing addr parameter");
+}
+$addr = $_GET["addr"];
+
+$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
+
+$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
+$res->execute(array($addr));
+$row = $res->fetch();
+if (!$row) {
+ die("No pending session for the specified MAC address");
+}
+$identity = $row[0];
+
+if (!$accept) {
+ print_header();
+
+ echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
+ readfile($t_c_file);
+} else {
+ $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
+ if (!$res->execute(array($t_c_timestamp, $identity))) {
+ die("Failed to update user account.");
+ }
+
+ $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
+ $res->execute(array($addr));
+
+ $fp = fsockopen($hostapd_ctrl);
+ if (!$fp) {
+ die("Could not connect to hostapd(AS)");
+ }
+
+ fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
+ fclose($fp);
+
+ $waiting = true;
+ $ack = false;
+ for ($i = 1; $i <= 10; $i++) {
+ $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
+ $res->execute(array($addr));
+ $row = $res->fetch();
+ if (!$row) {
+ die("No current session for the specified MAC address");
+ }
+ if (strlen($row[0]) > 0)
+ $waiting = $row[0] == 1;
+ if (strlen($row[1]) > 0)
+ $ack = $row[1] == 1;
+ $res->closeCursor();
+ if (!$waiting)
+ break;
+ sleep(1);
+ }
+ if ($ack) {
+ header('X-WFA-Hotspot20-Filtering: removed');
+ print_header();
+ echo "<p>Terms and conditions were accepted.</p>\n";
+
+ echo "<P>Filtering disabled.</P>\n";
+ } else {
+ print_header();
+ echo "<P>Failed to disable filtering.</P>\n";
+ }
+}
+
+?>
+
+</body>
+</html>
diff --git a/contrib/wpa/hs20/server/www/users.php b/contrib/wpa/hs20/server/www/users.php
new file mode 100644
index 000000000000..2bd555275dda
--- /dev/null
+++ b/contrib/wpa/hs20/server/www/users.php
@@ -0,0 +1,377 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_GET["id"])) {
+ $id = $_GET["id"];
+ if (!is_numeric($id))
+ $id = 0;
+} else
+ $id = 0;
+if (isset($_GET["cmd"]))
+ $cmd = $_GET["cmd"];
+else
+ $cmd = '';
+
+if ($cmd == 'eventlog' && $id > 0) {
+ $row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")->fetch();
+ $dump = $row['dump'];
+ if ($dump[0] == '<') {
+ header("Content-type: text/xml");
+ echo "<?xml version=\"1.0\"?>\n";
+ echo $dump;
+ } else {
+ header("Content-type: text/plain");
+ echo $dump;
+ }
+ exit;
+}
+
+if ($cmd == 'mo' && $id > 0) {
+ $mo = $_GET["mo"];
+ if (!isset($mo))
+ exit;
+ if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps")
+ exit;
+ $row = $db->query("SELECT $mo FROM users WHERE rowid=$id")->fetch();
+ header("Content-type: text/xml");
+ echo "<?xml version=\"1.0\"?>\n";
+ echo $row[$mo];
+ exit;
+}
+
+if ($cmd == 'cert' && $id > 0) {
+ $row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")->fetch();
+ header("Content-type: text/plain");
+ echo $row['cert_pem'];
+ exit;
+}
+
+?>
+
+<html>
+<head><title>HS 2.0 users</title></head>
+<body>
+
+<?php
+
+if ($cmd == 'subrem-clear' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='' WHERE rowid=$id");
+}
+if ($cmd == 'subrem-add-user' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='user' WHERE rowid=$id");
+}
+if ($cmd == 'subrem-add-machine' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id");
+}
+if ($cmd == 'subrem-add-reenroll' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id");
+}
+if ($cmd == 'subrem-add-policy' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
+}
+if ($cmd == 'subrem-add-free' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='free' WHERE rowid=$id");
+}
+if ($cmd == 'fetch-pps-on' && $id > 0) {
+ $db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id");
+}
+if ($cmd == 'fetch-pps-off' && $id > 0) {
+ $db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id");
+}
+if ($cmd == 'reset-pw' && $id > 0) {
+ $db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id");
+}
+if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) {
+ $policy = $_GET["policy"];
+ if ($policy == "no-policy" ||
+ is_readable("$osu_root/spp/policy/$policy.xml")) {
+ $db->exec("UPDATE users SET policy='$policy' WHERE rowid=$id");
+ }
+}
+if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) {
+ $type = $_GET["type"];
+ if ($type == "shared")
+ $db->exec("UPDATE users SET shared=1 WHERE rowid=$id");
+ if ($type == "default")
+ $db->exec("UPDATE users SET shared=0 WHERE rowid=$id");
+}
+
+if ($cmd == "set-osu-cred" && $id > 0) {
+ $osu_user = $_POST["osu_user"];
+ $osu_password = $_POST["osu_password"];
+ if (strlen($osu_user) == 0)
+ $osu_password = "";
+ $db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
+}
+
+if ($cmd == 'clear-t-c' && $id > 0) {
+ $db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
+}
+
+$dump = 0;
+
+if ($id > 0) {
+
+if (isset($_GET["dump"])) {
+ $dump = $_GET["dump"];
+ if (!is_numeric($dump))
+ $dump = 0;
+} else
+ $dump = 0;
+
+echo "[<a href=\"users.php\">All users</a>] ";
+if ($dump == 0)
+ echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>] ";
+else
+ echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] ";
+echo "<br>\n";
+
+$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch();
+
+echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n";
+
+echo "MO: ";
+if (strlen($row['devinfo']) > 0) {
+ echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n";
+}
+if (strlen($row['devdetail']) > 0) {
+ echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n";
+}
+if (strlen($row['pps']) > 0) {
+ echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n";
+}
+if (strlen($row['cert_pem']) > 0) {
+ echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n";
+}
+echo "<BR>\n";
+
+echo "Fetch PPS MO: ";
+if ($row['fetch_pps'] == "1") {
+ echo "On next connection " .
+ "[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" .
+ "do not fetch</a>]<br>\n";
+} else {
+ echo "Do not fetch " .
+ "[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" .
+ "request fetch</a>]<br>\n";
+}
+
+$cert = $row['cert'];
+if (strlen($cert) > 0) {
+ echo "Certificate fingerprint: $cert<br>\n";
+}
+
+echo "Remediation: ";
+$rem = $row['remediation'];
+if ($rem == "") {
+ echo "Not required";
+ echo " [<a href=\"users.php?cmd=subrem-add-user&id=" .
+ $row['rowid'] . "\">add:user</a>]";
+ echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
+ $row['rowid'] . "\">add:machine</a>]";
+ if ($row['methods'] == 'TLS') {
+ echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" .
+ $row['rowid'] . "\">add:reenroll</a>]";
+ }
+ echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
+ $row['rowid'] . "\">add:policy</a>]";
+ echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
+ $row['rowid'] . "\">add:free</a>]";
+} else if ($rem == "user") {
+ echo "User [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
+} else if ($rem == "policy") {
+ echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
+} else if ($rem == "free") {
+ echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
+} else if ($rem == "reenroll") {
+ echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
+} else {
+ echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
+}
+echo "<br>\n";
+
+if (strncmp($row['identity'], "cert-", 5) != 0)
+ echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
+
+echo "<form>Policy: <select name=\"policy\" " .
+ "onChange=\"window.location='users.php?cmd=policy&id=" .
+ $row['rowid'] . "&policy=' + this.value;\">\n";
+echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] .
+ "</option>\n";
+$files = scandir("$osu_root/spp/policy");
+foreach ($files as $file) {
+ if (!preg_match("/.xml$/", $file))
+ continue;
+ if ($file == $row['policy'] . ".xml")
+ continue;
+ $p = substr($file, 0, -4);
+ echo "<option value=\"$p\">$p</option>\n";
+}
+echo "<option value=\"no-policy\">no policy</option>\n";
+echo "</select></form>\n";
+
+echo "<form>Account type: <select name=\"type\" " .
+ "onChange=\"window.location='users.php?cmd=account-type&id=" .
+ $row['rowid'] . "&type=' + this.value;\">\n";
+if ($row['shared'] > 0) {
+ $default_sel = "";
+ $shared_sel = " selected";
+} else {
+ $default_sel = " selected";
+ $shared_sel = "";
+}
+echo "<option value=\"default\"$default_sel>default</option>\n";
+echo "<option value=\"shared\"$shared_sel>shared</option>\n";
+echo "</select></form>\n";
+
+echo "Phase 2 method(s): " . $row['methods'] . "<br>\n";
+
+echo "<br>\n";
+echo "<a href=\"users.php?cmd=reset-pw&id=" .
+ $row['rowid'] . "\">Reset AAA password</a><br>\n";
+
+echo "<br>\n";
+echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] .
+ "\" method=\"POST\">\n";
+echo "OSU credentials (if username empty, AAA credentials are used):<br>\n";
+echo "username: <input type=\"text\" name=\"osu_user\" value=\"" .
+ $row['osu_user'] . "\">\n";
+echo "password: <input type=\"password\" name=\"osu_password\">\n";
+echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
+echo "</form>\n";
+
+if (strlen($row['t_c_timestamp']) > 0) {
+ echo "<br>\n";
+ echo "<a href=\"users.php?cmd=clear-t-c&id=" .
+ $row['rowid'] .
+ "\">Clear Terms and Conditions acceptance</a><br>\n";
+}
+
+echo "<hr>\n";
+
+$user = $row['identity'];
+$osu_user = $row['osu_user'];
+$realm = $row['realm'];
+}
+
+if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) {
+
+ if ($id == 0) {
+ echo "[<a href=\"users.php\">All users</a>] ";
+ echo "<br>\n";
+ }
+
+echo "<table border=1>\n";
+echo "<tr>";
+if ($id == 0) {
+ echo "<th>user<th>realm";
+}
+echo "<th>time<th>address<th>sessionID<th>notes";
+if ($dump > 0)
+ echo "<th>dump";
+echo "\n";
+if (isset($_GET["limit"])) {
+ $limit = $_GET["limit"];
+ if (!is_numeric($limit))
+ $limit = 20;
+} else
+ $limit = 20;
+if ($id == 0)
+ $res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC LIMIT $limit");
+else if (strlen($osu_user) > 0)
+ $res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
+else
+ $res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
+foreach ($res as $row) {
+ echo "<tr>";
+ if ($id == 0) {
+ echo "<td>" . $row['user'] . "\n";
+ echo "<td>" . $row['realm'] . "\n";
+ }
+ echo "<td>" . $row['timestamp'] . "\n";
+ echo "<td>" . $row['addr'] . "\n";
+ echo "<td>" . $row['sessionid'] . "\n";
+ echo "<td>" . $row['notes'] . "\n";
+ $d = $row['dump'];
+ if (strlen($d) > 0) {
+ echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] .
+ "\">";
+ if ($d[0] == '<')
+ echo "XML";
+ else
+ echo "txt";
+ echo "</a>]\n";
+ if ($dump > 0)
+ echo "<td>" . htmlspecialchars($d) . "\n";
+ }
+}
+echo "</table>\n";
+
+}
+
+
+if ($id == 0 && $cmd != 'eventlog') {
+
+echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
+echo "<br>\n";
+
+echo "<table border=1 cellspacing=0 cellpadding=0>\n";
+echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
+
+$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity');
+foreach ($res as $row) {
+ echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
+ $row['identity'] . " </a>";
+ echo "<td>" . $row['realm'];
+ $rem = $row['remediation'];
+ echo "<td>";
+ if ($rem == "") {
+ echo "-";
+ } else if ($rem == "user") {
+ echo "User";
+ } else if ($rem == "policy") {
+ echo "Policy";
+ } else if ($rem == "free") {
+ echo "Free";
+ } else if ($rem == "reenroll") {
+ echo "Reenroll";
+ } else {
+ echo "Machine";
+ }
+ echo "<td>" . $row['policy'];
+ if ($row['shared'] > 0)
+ echo "<td>shared";
+ else
+ echo "<td>default";
+ echo "<td><small>" . $row['methods'] . "</small>";
+ echo "<td>";
+ $xml = xml_parser_create();
+ xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
+ foreach($devinfo as $k) {
+ if ($k['tag'] == 'DEVID') {
+ echo "<small>" . $k['value'] . "</small>";
+ break;
+ }
+ }
+ echo "<td><small>" . $row['mac_addr'] . "</small>";
+ echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
+ echo "\n";
+}
+echo "</table>\n";
+
+}
+
+?>
+
+</html>
diff --git a/contrib/wpa/src/Makefile b/contrib/wpa/src/Makefile
new file mode 100644
index 000000000000..6eb7f2acb5a1
--- /dev/null
+++ b/contrib/wpa/src/Makefile
@@ -0,0 +1,12 @@
+SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps
+SUBDIRS += fst
+
+all:
+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
+
+clean:
+ $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+ $(Q)rm -f *~
+
+install:
+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
diff --git a/contrib/wpa/src/ap/Makefile b/contrib/wpa/src/ap/Makefile
new file mode 100644
index 000000000000..a1e9b7c44d2f
--- /dev/null
+++ b/contrib/wpa/src/ap/Makefile
@@ -0,0 +1,60 @@
+CFLAGS += -DHOSTAPD
+CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_ETH_P_OUI
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R_AP
+CFLAGS += -DCONFIG_WPS
+CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IPV6
+CFLAGS += -DCONFIG_AIRTIME_POLICY
+
+LIB_OBJS= \
+ accounting.o \
+ ap_config.o \
+ ap_drv_ops.o \
+ ap_list.o \
+ ap_mlme.o \
+ airtime_policy.o \
+ authsrv.o \
+ beacon.o \
+ bss_load.o \
+ ctrl_iface_ap.o \
+ dfs.o \
+ dhcp_snoop.o \
+ drv_callbacks.o \
+ eap_user_db.o \
+ eth_p_oui.o \
+ gas_serv.o \
+ hostapd.o \
+ hs20.o \
+ hw_features.o \
+ ieee802_11_auth.o \
+ ieee802_11.o \
+ ieee802_11_ht.o \
+ ieee802_11_shared.o \
+ ieee802_11_vht.o \
+ ieee802_1x.o \
+ neighbor_db.o \
+ ndisc_snoop.o \
+ p2p_hostapd.o \
+ pmksa_cache_auth.o \
+ preauth_auth.o \
+ rrm.o \
+ sta_info.o \
+ tkip_countermeasures.o \
+ utils.o \
+ vlan.o \
+ vlan_ifconfig.o \
+ vlan_init.o \
+ wmm.o \
+ wnm_ap.o \
+ wpa_auth.o \
+ wpa_auth_ft.o \
+ wpa_auth_glue.o \
+ wpa_auth_ie.o \
+ wps_hostapd.o \
+ x_snoop.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c
index 11178a1f047c..a112045364e3 100644
--- a/contrib/wpa/src/ap/acs.c
+++ b/contrib/wpa/src/ap/acs.c
@@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
}
-void acs_cleanup(struct hostapd_iface *iface)
+static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
@@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
+}
+
+
+void acs_cleanup(struct hostapd_iface *iface)
+{
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++)
+ acs_cleanup_mode(&iface->hw_features[i]);
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
@@ -363,40 +372,47 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
}
-static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
+static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
{
- const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
- 157, 184, 192 };
+ const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620,
+ 5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035,
+ 6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355,
+ 6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675,
+ 6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995,
+ 7035, 7075 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
- if (chan->chan == allowed[i])
+ if (chan->freq == allowed[i])
return 1;
return 0;
}
-static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
+static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
{
- const int allowed[] = { 36, 52, 100, 116, 132, 149 };
+ const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035,
+ 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
+ 6755, 6835, 6915, 6995 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
- if (chan->chan == allowed[i])
+ if (chan->freq == allowed[i])
return 1;
return 0;
}
-static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
+static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
{
- const int allowed[] = { 36, 100 };
+ const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755,
+ 6915 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
- if (chan->chan == allowed[i])
+ if (chan->freq == allowed[i])
return 1;
return 0;
@@ -453,21 +469,35 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
}
-static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- int valid = 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
acs_survey_list_is_sufficient(chan))
- valid++;
+ return 1;
}
- /* We need at least survey data for one channel */
- return !!valid;
+ return 0;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode) &&
+ acs_surveys_are_sufficient_mode(mode))
+ return 1;
+ }
+
+ return 0;
}
@@ -489,14 +519,25 @@ static int is_in_chanlist(struct hostapd_iface *iface,
}
-static void acs_survey_all_chans_intereference_factor(
- struct hostapd_iface *iface)
+static int is_in_freqlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ if (!iface->conf->acs_freq_list.num)
+ return 1;
+
+ return freq_range_list_includes(&iface->conf->acs_freq_list,
+ chan->freq);
+}
+
+
+static void acs_survey_mode_interference_factor(
+ struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!acs_usable_chan(chan))
continue;
@@ -504,6 +545,9 @@ static void acs_survey_all_chans_intereference_factor(
if (!is_in_chanlist(iface, chan))
continue;
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -515,14 +559,28 @@ static void acs_survey_all_chans_intereference_factor(
}
-static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
- int freq)
+static void acs_survey_all_chans_interference_factor(
+ struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_survey_mode_interference_factor(iface, mode);
+ }
+}
+
+
+static struct hostapd_channel_data *
+acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
{
struct hostapd_channel_data *chan;
int i;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
@@ -535,6 +593,26 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
}
+static struct hostapd_channel_data *
+acs_find_chan(struct hostapd_iface *iface, int freq)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode)) {
+ chan = acs_find_chan_mode(mode, freq);
+ if (chan)
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+
static int is_24ghz_mode(enum hostapd_hw_mode mode)
{
return mode == HOSTAPD_MODE_IEEE80211B ||
@@ -565,58 +643,24 @@ static int is_common_24ghz_chan(int chan)
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
-/*
- * At this point it's assumed chan->interface_factor has been computed.
- * This function should be reusable regardless of interference computation
- * option (survey, BSS, spectral, ...). chan->interference factor must be
- * summable (i.e., must be always greater than zero).
- */
-static struct hostapd_channel_data *
-acs_find_ideal_chan(struct hostapd_iface *iface)
+static void
+acs_find_ideal_chan_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int n_chans, u32 bw,
+ struct hostapd_channel_data **rand_chan,
+ struct hostapd_channel_data **ideal_chan,
+ long double *ideal_factor)
{
- struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
- *rand_chan = NULL;
- long double factor, ideal_factor = 0;
+ struct hostapd_channel_data *chan, *adj_chan = NULL;
+ long double factor;
int i, j;
- int n_chans = 1;
- u32 bw;
unsigned int k;
- /* TODO: HT40- support */
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel == -1) {
- wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
- return NULL;
- }
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel)
- n_chans = 2;
-
- if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
- switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_80MHZ:
- n_chans = 4;
- break;
- case CHANWIDTH_160MHZ:
- n_chans = 8;
- break;
- }
- }
-
- bw = num_chan_to_bw(n_chans);
-
- /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
-
- wpa_printf(MSG_DEBUG,
- "ACS: Survey analysis for selected bandwidth %d MHz", bw);
-
- for (i = 0; i < iface->current_mode->num_channels; i++) {
+ for (i = 0; i < mode->num_channels; i++) {
double total_weight;
struct acs_bias *bias, tmp_bias;
- chan = &iface->current_mode->channels[i];
+ chan = &mode->channels[i];
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
@@ -628,6 +672,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
if (!is_in_chanlist(iface, chan))
continue;
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
if (!chan_bw_allowed(chan, bw, 1, 1)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported",
@@ -637,31 +684,33 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211n &&
- iface->conf->secondary_channel &&
- !acs_usable_ht40_chan(chan)) {
- wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40",
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ ((iface->conf->ieee80211n &&
+ iface->conf->secondary_channel) ||
+ is_6ghz_freq(chan->freq)) &&
+ !acs_usable_bw40_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
chan->chan);
continue;
}
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ &&
- !acs_usable_vht80_chan(chan)) {
+ !acs_usable_bw80_chan(chan)) {
wpa_printf(MSG_DEBUG,
- "ACS: Channel %d: not allowed as primary channel for VHT80",
+ "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
chan->chan);
continue;
}
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_160MHZ &&
- !acs_usable_vht160_chan(chan)) {
+ !acs_usable_bw160_chan(chan)) {
wpa_printf(MSG_DEBUG,
- "ACS: Channel %d: not allowed as primary channel for VHT160",
+ "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
chan->chan);
continue;
}
@@ -698,7 +747,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
- if (is_24ghz_mode(iface->current_mode->mode)) {
+ if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
@@ -744,7 +793,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
break;
bias = NULL;
}
- } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ } else if (is_24ghz_mode(mode->mode) &&
is_common_24ghz_chan(chan->chan)) {
tmp_bias.channel = chan->chan;
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
@@ -763,14 +812,78 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
if (acs_usable_chan(chan) &&
- (!ideal_chan || factor < ideal_factor)) {
- ideal_factor = factor;
- ideal_chan = chan;
+ (!*ideal_chan || factor < *ideal_factor)) {
+ *ideal_factor = factor;
+ *ideal_chan = chan;
}
/* This channel would at least be usable */
- if (!rand_chan)
- rand_chan = chan;
+ if (!(*rand_chan))
+ *rand_chan = chan;
+ }
+}
+
+
+/*
+ * At this point it's assumed chan->interference_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *ideal_chan = NULL,
+ *rand_chan = NULL;
+ long double ideal_factor = 0;
+ int i;
+ int n_chans = 1;
+ u32 bw;
+ struct hostapd_hw_modes *mode;
+
+ if (is_6ghz_op_class(iface->conf->op_class)) {
+ bw = op_class_to_bandwidth(iface->conf->op_class);
+ n_chans = bw / 20;
+ goto bw_selected;
+ }
+
+ /* TODO: HT40- support */
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel == -1) {
+ wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+ return NULL;
+ }
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
+
+ bw = num_chan_to_bw(n_chans);
+
+bw_selected:
+ /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
+ &rand_chan, &ideal_chan,
+ &ideal_factor);
}
if (ideal_chan) {
@@ -826,7 +939,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
return -1;
}
- acs_survey_all_chans_intereference_factor(iface);
+ acs_survey_all_chans_interference_factor(iface);
return 0;
}
@@ -862,6 +975,7 @@ static void acs_study(struct hostapd_iface *iface)
}
iface->conf->channel = ideal_chan->chan;
+ iface->freq = ideal_chan->freq;
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
acs_adjust_center_freq(iface);
@@ -917,31 +1031,67 @@ fail:
}
+static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int *freq)
+{
+ struct hostapd_channel_data *chan;
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
+ *freq++ = chan->freq;
+ }
+
+ return freq;
+}
+
+
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
- struct hostapd_channel_data *chan;
int i, *freq;
+ int num_channels;
+ struct hostapd_hw_modes *mode;
os_memset(&params, 0, sizeof(params));
- params.freqs = os_calloc(iface->current_mode->num_channels + 1,
- sizeof(params.freqs[0]));
+
+ num_channels = 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ num_channels += mode->num_channels;
+ }
+
+ params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- continue;
-
- if (!is_in_chanlist(iface, chan))
- continue;
- *freq++ = chan->freq;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ freq = acs_request_scan_add_freqs(iface, mode, freq);
}
+
*freq = 0;
+ if (params.freqs == freq) {
+ wpa_printf(MSG_ERROR, "ACS: No available channels found");
+ os_free(params.freqs);
+ return -1;
+ }
+
iface->scan_cb = acs_scan_complete;
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
@@ -971,7 +1121,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS;
}
- if (!iface->current_mode)
+ if (!iface->current_mode &&
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface);
diff --git a/contrib/wpa/src/ap/airtime_policy.c b/contrib/wpa/src/ap/airtime_policy.c
index f56ca5bddc3f..abe817c5b015 100644
--- a/contrib/wpa/src/ap/airtime_policy.c
+++ b/contrib/wpa/src/ap/airtime_policy.c
@@ -79,6 +79,10 @@ static void count_backlogged_sta(struct hostapd_data *hapd)
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
continue;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->force_backlog_bytes)
+ data.backlog_bytes = 1;
+#endif /* CONFIG_TESTING_OPTIONS */
if (data.backlog_bytes > 0)
set_new_backlog_time(hapd, sta, &now);
@@ -134,8 +138,8 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
wt_sum = 0;
unsigned int quantum;
- Boolean all_div_min = TRUE;
- Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
+ bool all_div_min = true;
+ bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
int wt, num_bss = 0, max_wt = 0;
size_t i;
@@ -169,7 +173,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
* integers. */
if (bss->num_backlogged_sta &&
bss->num_backlogged_sta % num_sta_min > 0)
- all_div_min = FALSE;
+ all_div_min = false;
/* If we're in LIMIT mode, we only apply the weight
* scaling when the BSS(es) marked as limited would a
@@ -178,7 +182,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
if (!apply_limit && bss->conf->airtime_limit) {
if (bss->num_backlogged_sta * wt_sum >
bss->conf->airtime_weight * num_sta_sum)
- apply_limit = TRUE;
+ apply_limit = true;
}
}
if (all_div_min)
diff --git a/contrib/wpa/src/ap/ap_config.c b/contrib/wpa/src/ap/ap_config.c
index 90348e1ddb97..7b6d54c35fc2 100644
--- a/contrib/wpa/src/ap/ap_config.c
+++ b/contrib/wpa/src/ap/ap_config.c
@@ -16,6 +16,7 @@
#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
+#include "common/sae.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -53,23 +54,33 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->logger_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1;
+#ifdef CONFIG_WEP
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2;
+#else /* CONFIG_WEP */
+ bss->auth_algs = WPA_AUTH_ALG_OPEN;
+#endif /* CONFIG_WEP */
bss->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
bss->wpa_group_update_count = 4;
bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries =
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_NO_TKIP
+ bss->wpa_pairwise = WPA_CIPHER_CCMP;
+ bss->wpa_group = WPA_CIPHER_CCMP;
+#else /* CONFIG_NO_TKIP */
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = 0;
bss->max_num_sta = MAX_STA_COUNT;
@@ -86,11 +97,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->pwd_group = 19; /* ECC: GF(p=256) */
-#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
@@ -112,7 +121,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->radius_das_time_window = 300;
- bss->sae_anti_clogging_threshold = 5;
+ bss->anti_clogging_threshold = 5;
bss->sae_sync = 5;
bss->gas_frag_limit = 1400;
@@ -122,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->fils_hlp_wait_time = 30;
bss->dhcp_server_port = DHCP_SERVER_PORT;
bss->dhcp_relay_port = DHCP_SERVER_PORT;
+ bss->fils_discovery_min_int = 20;
#endif /* CONFIG_FILS */
bss->broadcast_deauth = 1;
@@ -135,6 +145,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+ bss->max_auth_rounds = 100;
+ bss->max_auth_rounds_short = 50;
+
bss->send_probe_response = 1;
#ifdef CONFIG_HS20
@@ -148,6 +161,15 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bss->sae_commit_status = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_PASN
+ /* comeback after 10 TUs */
+ bss->pasn_comeback_after = 10;
+#endif /* CONFIG_PASN */
}
@@ -249,6 +271,14 @@ struct hostapd_config * hostapd_config_defaults(void)
HE_OPERATION_RTS_THRESHOLD_OFFSET;
/* Set default basic MCS/NSS set to single stream MCS 0-7 */
conf->he_op.he_basic_mcs_nss_set = 0xfffc;
+ conf->he_op.he_bss_color_disabled = 1;
+ conf->he_op.he_bss_color_partial = 0;
+ conf->he_op.he_bss_color = 1;
+ conf->he_op.he_twt_responder = 1;
+ conf->he_6ghz_max_mpdu = 2;
+ conf->he_6ghz_max_ampdu_len_exp = 7;
+ conf->he_6ghz_rx_ant_pat = 1;
+ conf->he_6ghz_tx_ant_pat = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -299,6 +329,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
+ int wps = 0;
line++;
@@ -329,6 +360,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
+ } else if (!os_strcmp(name, "wps")) {
+ wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@@ -346,8 +379,9 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (!token)
token = "";
if (hwaddr_aton(token, addr)) {
- wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", token, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid MAC address '%s' on line %d in '%s'",
+ token, line, fname);
ret = -1;
break;
}
@@ -375,16 +409,17 @@ static int hostapd_config_read_wpa_psk(const char *fname,
ok = 0;
len = os_strlen(pos);
- if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ if (len == 2 * PMK_LEN &&
+ hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
- else if (len >= 8 && len < 64) {
- pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
- 4096, psk->psk, PMK_LEN);
+ else if (len >= 8 && len < 64 &&
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN) == 0)
ok = 1;
- }
if (!ok) {
- wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
- "'%s'", pos, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid PSK '%s' on line %d in '%s'",
+ pos, line, fname);
os_free(psk);
ret = -1;
break;
@@ -402,6 +437,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
}
+ psk->wps = wps;
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -433,10 +470,53 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
}
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE
+ struct hostapd_ssid *ssid = &conf->ssid;
+ struct sae_password_entry *pw;
+
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !hostapd_sae_pk_in_use(conf)) ||
+ conf->sae_pwe == 3 ||
+ !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
+ return 0; /* PT not needed */
+
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ if (ssid->wpa_passphrase) {
+ ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase),
+ NULL);
+ if (!ssid->pt)
+ return -1;
+ }
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ sae_deinit_pt(pw->pt);
+ pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) pw->password,
+ os_strlen(pw->password),
+ pw->identifier);
+ if (!pw->pt)
+ return -1;
+ }
+#endif /* CONFIG_SAE */
+
+ return 0;
+}
+
+
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
+ if (hostapd_setup_sae_pt(conf) < 0)
+ return -1;
+
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@@ -581,6 +661,7 @@ void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
}
+#ifdef CONFIG_WEP
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -589,6 +670,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
keys->key[i] = NULL;
}
}
+#endif /* CONFIG_WEP */
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
@@ -642,6 +724,12 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
pw = pw->next;
str_clear_free(tmp->password);
os_free(tmp->identifier);
+#ifdef CONFIG_SAE
+ sae_deinit_pt(tmp->pt);
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(tmp->pk);
+#endif /* CONFIG_SAE_PK */
os_free(tmp);
}
}
@@ -674,10 +762,15 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_WEP
hostapd_config_free_wep(&conf->ssid.wep);
+#endif /* CONFIG_WEP */
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#ifdef CONFIG_SAE
+ sae_deinit_pt(conf->ssid.pt);
+#endif /* CONFIG_SAE */
hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
@@ -692,6 +785,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
+ os_free(conf->radius->force_client_dev);
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
@@ -765,6 +859,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->upc);
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
+ wpabuf_free(conf->wps_application_ext);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -832,6 +927,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override);
+ wpabuf_free(conf->rsne_override_eapol);
+ wpabuf_free(conf->rsnxe_override_eapol);
+ wpabuf_free(conf->rsne_override_ft);
+ wpabuf_free(conf->rsnxe_override_ft);
+ wpabuf_free(conf->gtk_rsc_override);
+ wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@@ -840,6 +941,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
hostapd_config_free_fils_realms(conf);
#ifdef CONFIG_DPP
+ os_free(conf->dpp_name);
+ os_free(conf->dpp_mud_url);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
@@ -864,6 +967,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
#endif /* CONFIG_AIRTIME_POLICY */
+#ifdef CONFIG_PASN
+ os_free(conf->pasn_groups);
+#endif /* CONFIG_PASN */
+
os_free(conf);
}
@@ -885,6 +992,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->acs_ch_list.range);
+ os_free(conf->acs_freq_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@@ -1027,10 +1135,85 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
}
+#ifdef CONFIG_SAE_PK
+static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
+{
+ struct sae_password_entry *pw;
+ bool res = false;
+
+ if (bss->ssid.wpa_passphrase &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(bss->ssid.wpa_passphrase))
+ res = true;
+
+ for (pw = bss->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(pw->password))
+ return true;
+
+ if (bss->ssid.wpa_passphrase && res && pw->pk &&
+ os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0)
+ res = false;
+ }
+
+ return res;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
+{
+ if (bss->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_ERROR,
+ "Pre-RSNA security methods are not allowed in 6 GHz");
+ return false;
+ }
+
+ if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_printf(MSG_ERROR,
+ "Management frame protection is required in 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) {
+ wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR,
+ "Invalid pairwise cipher suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_group & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz");
+ return false;
+ }
+
+ return true;
+}
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
{
+ if (full_config && is_6ghz_op_class(conf->op_class) &&
+ !hostapd_config_check_bss_6g(bss))
+ return -1;
+
if (full_config && bss->ieee802_1x && !bss->eap_server &&
!bss->radius->auth_servers) {
wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@@ -1038,6 +1221,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
+#ifdef CONFIG_WEP
if (bss->wpa) {
int wep, i;
@@ -1055,6 +1239,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@@ -1102,52 +1287,75 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities");
}
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ac && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+#ifdef CONFIG_WEP
+ if (full_config && conf->ieee80211ax &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities");
+ }
+#endif /* CONFIG_WEP */
+
+ if (full_config && conf->ieee80211ax && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities");
+ }
+#endif /* CONFIG_IEEE80211AX */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@@ -1155,12 +1363,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
bss->wps_state = 0;
}
+#ifdef CONFIG_WEP
if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled");
bss->wps_state = 0;
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
@@ -1204,6 +1414,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_SAE_PK
+ if (full_config && hostapd_sae_pk_in_use(bss) &&
+ hostapd_sae_pk_password_without_pk(bss)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
+ return -1;
+ }
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
@@ -1284,11 +1503,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config)
{
+#ifdef CONFIG_WEP
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
+#endif /* CONFIG_WEP */
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
@@ -1314,6 +1535,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
} else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+#ifdef CONFIG_WEP
bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
@@ -1324,11 +1546,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
else
cipher = WPA_CIPHER_WEP40;
}
+#endif /* CONFIG_WEP */
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+#ifdef CONFIG_WEP
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
@@ -1339,6 +1563,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+#endif /* CONFIG_WEP */
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -1377,3 +1602,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
return 2;
return with_id;
}
+
+
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE_PK
+ struct sae_password_entry *pw;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->pk)
+ return true;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ return false;
+}
+
+
+#ifdef CONFIG_SAE_PK
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
+{
+ bool with_pk = false;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ return false;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk)
+ return false;
+ with_pk = true;
+ }
+
+ return with_pk;
+}
+#endif /* CONFIG_SAE_PK */
diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h
index ea581a822277..ced36f9cc828 100644
--- a/contrib/wpa/src/ap/ap_config.h
+++ b/contrib/wpa/src/ap/ap_config.h
@@ -67,6 +67,7 @@ struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@@ -75,10 +76,13 @@ struct hostapd_wep_keys {
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
+#endif /* CONFIG_WEP */
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
+#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1,
+#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
@@ -88,6 +92,7 @@ typedef enum hostap_security_policy {
struct hostapd_ssid {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
+ u32 short_ssid;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
@@ -99,8 +104,11 @@ struct hostapd_ssid {
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
+ struct sae_pt *pt;
+#ifdef CONFIG_WEP
struct hostapd_wep_keys wep;
+#endif /* CONFIG_WEP */
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
@@ -150,6 +158,7 @@ struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
+ int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -188,15 +197,6 @@ struct hostapd_radius_attr {
#define NUM_TX_QUEUES 4
-
-struct hostapd_tx_queue_params {
- int aifs;
- int cwmin;
- int cwmax;
- int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-};
-
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium {
@@ -251,6 +251,8 @@ struct sae_password_entry {
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
+ struct sae_pt *pt;
+ struct sae_pk *pk;
};
struct dpp_controller_conf {
@@ -265,6 +267,8 @@ struct airtime_sta_weight {
u8 addr[ETH_ALEN];
};
+#define EXT_CAPA_MAX_LEN 15
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -317,18 +321,16 @@ struct hostapd_bss_config {
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
+#ifdef CONFIG_WEP
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
+#endif /* CONFIG_WEP */
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
- int ieee802_11f; /* use IEEE 802.11f (IAPP) */
- char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
- * frames */
-
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
@@ -346,15 +348,15 @@ struct hostapd_bss_config {
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int extended_key_id;
int wpa_key_mgmt;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -371,6 +373,7 @@ struct hostapd_bss_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -415,6 +418,8 @@ struct hostapd_bss_config {
unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
@@ -429,6 +434,8 @@ struct hostapd_bss_config {
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ int eap_teap_id;
int eap_sim_aka_result_ind;
int eap_sim_id;
int tnc;
@@ -497,6 +504,7 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *wps_application_ext;
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
@@ -525,8 +533,9 @@ struct hostapd_bss_config {
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
- int disable_11n;
- int disable_11ac;
+ bool disable_11n;
+ bool disable_11ac;
+ bool disable_11ax;
/* IEEE 802.11v */
int time_advertisement;
@@ -648,9 +657,11 @@ struct hostapd_bss_config {
struct wpabuf *vendor_elements;
struct wpabuf *assocresp_elements;
- unsigned int sae_anti_clogging_threshold;
+ unsigned int anti_clogging_threshold;
unsigned int sae_sync;
int sae_require_mfp;
+ int sae_confirm_immediate;
+ int sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@@ -661,7 +672,26 @@ struct hostapd_bss_config {
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
int sae_reflection_attack;
+ int sae_commit_status;
+ int sae_pk_omit;
+ int sae_pk_password_check_skip;
struct wpabuf *sae_commit_override;
+ struct wpabuf *rsne_override_eapol;
+ struct wpabuf *rsnxe_override_eapol;
+ struct wpabuf *rsne_override_ft;
+ struct wpabuf *rsnxe_override_ft;
+ struct wpabuf *gtk_rsc_override;
+ struct wpabuf *igtk_rsc_override;
+ int no_beacon_rsnxe;
+ int skip_prune_assoc;
+ int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -702,19 +732,27 @@ struct hostapd_bss_config {
unsigned int fils_hlp_wait_time;
u16 dhcp_server_port;
u16 dhcp_relay_port;
+ u32 fils_discovery_min_int;
+ u32 fils_discovery_max_int;
#endif /* CONFIG_FILS */
int multicast_to_unicast;
int broadcast_deauth;
+ int notify_mgmt_frames;
+
#ifdef CONFIG_DPP
+ char *dpp_name;
+ char *dpp_mud_url;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
+ int dpp_configurator_connectivity;
+ int dpp_pfs;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -724,12 +762,15 @@ struct hostapd_bss_config {
size_t owe_transition_ssid_len;
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
+ int owe_ptk_workaround;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
u8 send_probe_response;
+ u8 transition_disable;
+
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@@ -827,15 +868,41 @@ struct hostapd_bss_config {
*/
u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+
+ /* If set, corrupt the MIC in the 2nd Authentication frame of PASN */
+ int pasn_corrupt_mic;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ int *pasn_groups;
+
+ /*
+ * The time in TUs after which the non-AP STA is requested to retry the
+ * PASN authentication in case there are too many parallel operations.
+ */
+ u16 pasn_comeback_after;
+#endif /* CONFIG_PASN */
+
+ unsigned int unsol_bcast_probe_resp_interval;
+
+ u8 ext_capa_mask[EXT_CAPA_MAX_LEN];
+ u8 ext_capa[EXT_CAPA_MAX_LEN];
};
/**
* struct he_phy_capabilities_info - HE PHY capabilities
*/
struct he_phy_capabilities_info {
- Boolean he_su_beamformer;
- Boolean he_su_beamformee;
- Boolean he_mu_beamformer;
+ bool he_su_beamformer;
+ bool he_su_beamformee;
+ bool he_mu_beamformer;
};
/**
@@ -843,8 +910,11 @@ struct he_phy_capabilities_info {
*/
struct he_operation {
u8 he_bss_color;
+ u8 he_bss_color_disabled;
+ u8 he_bss_color_partial;
u8 he_default_pe_duration;
u8 he_twt_required;
+ u8 he_twt_responder;
u16 he_rts_threshold;
u16 he_basic_mcs_nss_set;
};
@@ -857,8 +927,8 @@ struct spatial_reuse {
u8 non_srg_obss_pd_max_offset;
u8 srg_obss_pd_min_offset;
u8 srg_obss_pd_max_offset;
- u8 srg_obss_color_bitmap;
- u8 srg_obss_color_partial_bitmap;
+ u8 srg_bss_color_bitmap[8];
+ u8 srg_partial_bssid_bitmap[8];
};
/**
@@ -871,11 +941,17 @@ struct hostapd_config {
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
+ u8 op_class;
u8 channel;
+ int enable_edmg;
+ u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
+ struct wpa_freq_range_list acs_freq_list;
+ u8 acs_freq_list_present;
int acs_exclude_dfs;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ int acs_exclude_6ghz_non_psc;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -987,6 +1063,10 @@ struct hostapd_config {
u8 he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
+ u8 he_6ghz_max_mpdu;
+ u8 he_6ghz_max_ampdu_len_exp;
+ u8 he_6ghz_rx_ant_pat;
+ u8 he_6ghz_tx_ant_pat;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -994,8 +1074,14 @@ struct hostapd_config {
#define CH_SWITCH_VHT_DISABLED BIT(1)
unsigned int ch_switch_vht_config;
+ /* HE enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_HE_ENABLED BIT(0)
+#define CH_SWITCH_HE_DISABLED BIT(1)
+ unsigned int ch_switch_he_config;
+
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
+ int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY
enum {
@@ -1100,5 +1186,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/contrib/wpa/src/ap/ap_drv_ops.c b/contrib/wpa/src/ap/ap_drv_ops.c
index c0ededabe979..d1642d7dff15 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.c
+++ b/contrib/wpa/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
@@ -107,6 +108,10 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
#endif /* CONFIG_FILS */
+ pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
+
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
goto fail;
@@ -305,9 +310,7 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
-#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, &params);
}
@@ -348,7 +351,7 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
- return 0;
+ return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@@ -415,6 +418,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
{
@@ -436,6 +440,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
+ params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
@@ -540,7 +545,8 @@ int hostapd_flush(struct hostapd_data *hapd)
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
@@ -548,7 +554,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
struct hostapd_freq_params data;
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+ edmg_channel, ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
center_segment0, center_segment1,
@@ -583,7 +590,7 @@ int hostapd_set_frag(struct hostapd_data *hapd, int frag)
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and)
{
- if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
@@ -645,6 +652,12 @@ int hostapd_drv_none(struct hostapd_data *hapd)
}
+bool hostapd_drv_nl80211(struct hostapd_data *hapd)
+{
+ return hapd->driver && os_strcmp(hapd->driver->name, "nl80211") == 0;
+}
+
+
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params)
{
@@ -675,36 +688,41 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
+ struct wpa_driver_set_key_params params;
+
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
- return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
- key_idx, set_tx, seq, seq_len, key,
- key_len);
-}
+ os_memset(&params, 0, sizeof(params));
+ params.ifname = ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.vlan_id = vlan_id;
+ params.key_flag = key_flag;
-int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack)
-{
- if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
- return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- NULL, 0);
+ return hapd->driver->set_key(hapd->drv_priv, &params);
}
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len)
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt)
{
- if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- csa_offs, csa_offs_len);
+ csa_offs, csa_offs_len, no_encrypt, 0);
}
@@ -810,7 +828,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
return -1;
}
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+ ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
@@ -850,10 +869,24 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
- if ((acs_ch_list_all ||
- freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
- chan->chan)) &&
- !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ if (!acs_ch_list_all &&
+ (hapd->iface->conf->acs_freq_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_freq_list,
+ chan->freq)))
+ continue;
+ if (!acs_ch_list_all &&
+ (!hapd->iface->conf->acs_freq_list_present &&
+ hapd->iface->conf->acs_ch_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_ch_list,
+ chan->chan)))
+ continue;
+ if (is_6ghz_freq(chan->freq) &&
+ hapd->iface->conf->acs_exclude_6ghz_non_psc &&
+ !is_6ghz_psc_frequency(chan->freq))
+ continue;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
!(hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR)))
int_array_add_unique(freq_list, chan->freq);
@@ -879,10 +912,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
int ret, i, acs_ch_list_all = 0;
- u8 *channels = NULL;
- unsigned int num_channels = 0;
struct hostapd_hw_modes *mode;
int *freq_list = NULL;
+ enum hostapd_hw_mode selected_mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
@@ -894,42 +926,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
* If no chanlist config parameter is provided, include all enabled
* channels of the selected hw_mode.
*/
- if (!hapd->iface->conf->acs_ch_list.num)
- acs_ch_list_all = 1;
-
- mode = hapd->iface->current_mode;
- if (mode) {
- channels = os_malloc(mode->num_channels);
- if (channels == NULL)
- return -1;
-
- for (i = 0; i < mode->num_channels; i++) {
- struct hostapd_channel_data *chan = &mode->channels[i];
- if (!acs_ch_list_all &&
- !freq_range_list_includes(
- &hapd->iface->conf->acs_ch_list,
- chan->chan))
- continue;
- if (hapd->iface->conf->acs_exclude_dfs &&
- (chan->flag & HOSTAPD_CHAN_RADAR))
- continue;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
- channels[num_channels++] = chan->chan;
- int_array_add_unique(&freq_list, chan->freq);
- }
- }
- } else {
- for (i = 0; i < hapd->iface->num_hw_features; i++) {
- mode = &hapd->iface->hw_features[i];
- hostapd_get_hw_mode_any_channels(hapd, mode,
- acs_ch_list_all,
- &freq_list);
- }
+ if (hapd->iface->conf->acs_freq_list_present)
+ acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num;
+ else
+ acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num;
+
+ if (hapd->iface->current_mode)
+ selected_mode = hapd->iface->current_mode->mode;
+ else
+ selected_mode = HOSTAPD_MODE_IEEE80211ANY;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ mode = &hapd->iface->hw_features[i];
+ if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ selected_mode != mode->mode)
+ continue;
+ hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
+ &freq_list);
}
- params.ch_list = channels;
- params.ch_list_len = num_channels;
params.freq_list = freq_list;
+ params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
@@ -953,8 +970,11 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
params.ch_width = 160;
}
+ if (hapd->iface->conf->op_class)
+ params.ch_width = op_class_to_bandwidth(
+ hapd->iface->conf->op_class);
ret = hapd->driver->do_acs(hapd->drv_priv, &params);
- os_free(channels);
+ os_free(freq_list);
return ret;
}
@@ -968,3 +988,11 @@ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
ie, ielen);
}
+
+
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
+{
+ if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->dpp_listen(hapd->drv_priv, enable);
+}
diff --git a/contrib/wpa/src/ap/ap_drv_ops.h b/contrib/wpa/src/ap/ap_drv_ops.h
index ca7f7abe01fd..61c8f64eb471 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.h
+++ b/contrib/wpa/src/ap/ap_drv_ops.h
@@ -43,6 +43,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@@ -62,7 +63,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
int he_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@@ -79,6 +81,7 @@ hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags, u8 *dfs_domain);
int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_drv_none(struct hostapd_data *hapd);
+bool hostapd_drv_nl80211(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params);
struct wpa_scan_results * hostapd_driver_get_scan_results(
@@ -88,14 +91,13 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack);
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len);
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -132,6 +134,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
#include "drivers/driver.h"
@@ -348,12 +351,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
+ enum nested_attr nested_attr_flag,
struct wpabuf *buf)
{
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
- data_len, buf);
+ data_len, nested_attr_flag, buf);
}
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
@@ -381,4 +385,35 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
}
+static inline int
+hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
+{
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
+ return -1;
+ return hapd->driver->set_band(hapd->drv_priv, band_mask);
+}
+
+#ifdef ANDROID
+static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd,
+ char *cmd, char *buf, size_t buf_len)
+{
+ if (!hapd->driver->driver_cmd)
+ return -1;
+ return hapd->driver->driver_cmd(hapd->drv_priv, cmd, buf, buf_len);
+}
+#endif /* ANDROID */
+
+#ifdef CONFIG_TESTING_OPTIONS
+static inline int
+hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
+ const u8 *match, size_t match_len,
+ bool multicast)
+{
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->register_frame)
+ return -1;
+ return hapd->driver->register_frame(hapd->drv_priv, type, match,
+ match_len, multicast);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
#endif /* AP_DRV_OPS */
diff --git a/contrib/wpa/src/ap/ap_list.c b/contrib/wpa/src/ap/ap_list.c
index 8bf6ddec8d37..20be7f8f881d 100644
--- a/contrib/wpa/src/ap/ap_list.c
+++ b/contrib/wpa/src/ap/ap_list.c
@@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
@@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_update_beacons(iface);
@@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
iface->olbc = 0;
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
diff --git a/contrib/wpa/src/ap/authsrv.c b/contrib/wpa/src/ap/authsrv.c
index 4f5fe7db4482..8e12daf40a46 100644
--- a/contrib/wpa/src/ap/authsrv.c
+++ b/contrib/wpa/src/ap/authsrv.c
@@ -110,28 +110,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
- srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
- srv.ssl_ctx = hapd->ssl_ctx;
- srv.msg_ctx = hapd->msg_ctx;
- srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
- srv.eap_fast_a_id = conf->eap_fast_a_id;
- srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
- srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
- srv.eap_fast_prov = conf->eap_fast_prov;
- srv.pac_key_lifetime = conf->pac_key_lifetime;
- srv.pac_key_refresh_time = conf->pac_key_refresh_time;
- srv.eap_teap_auth = conf->eap_teap_auth;
- srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- srv.eap_sim_id = conf->eap_sim_id;
- srv.tnc = conf->tnc;
- srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
- srv.pwd_group = conf->pwd_group;
- srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
@@ -142,10 +124,8 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
- srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
- srv.tls_session_lifetime = conf->tls_session_lifetime;
- srv.tls_flags = conf->tls_flags;
+ srv.eap_cfg = hapd->eap_cfg;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -193,6 +173,60 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev,
#endif /* EAP_TLS_FUNCS */
+static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
+{
+ struct eap_config *cfg;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (!cfg)
+ return NULL;
+
+ cfg->eap_server = hapd->conf->eap_server;
+ cfg->ssl_ctx = hapd->ssl_ctx;
+ cfg->msg_ctx = hapd->msg_ctx;
+ cfg->eap_sim_db_priv = hapd->eap_sim_db_priv;
+ cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ cfg->tls_flags = hapd->conf->tls_flags;
+ cfg->max_auth_rounds = hapd->conf->max_auth_rounds;
+ cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short;
+ if (hapd->conf->pac_opaque_encr_key)
+ cfg->pac_opaque_encr_key =
+ os_memdup(hapd->conf->pac_opaque_encr_key, 16);
+ if (hapd->conf->eap_fast_a_id) {
+ cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id,
+ hapd->conf->eap_fast_a_id_len);
+ cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+ }
+ if (hapd->conf->eap_fast_a_id_info)
+ cfg->eap_fast_a_id_info =
+ os_strdup(hapd->conf->eap_fast_a_id_info);
+ cfg->eap_fast_prov = hapd->conf->eap_fast_prov;
+ cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
+ cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
+ cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
+ cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
+ cfg->eap_teap_id = hapd->conf->eap_teap_id;
+ cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+ cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->tnc = hapd->conf->tnc;
+ cfg->wps = hapd->wps;
+ cfg->fragment_size = hapd->conf->fragment_size;
+ cfg->pwd_group = hapd->conf->pwd_group;
+ cfg->pbc_in_m1 = hapd->conf->pbc_in_m1;
+ if (hapd->conf->server_id) {
+ cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id);
+ cfg->server_id_len = os_strlen(hapd->conf->server_id);
+ } else {
+ cfg->server_id = (u8 *) os_strdup("hostapd");
+ cfg->server_id_len = 7;
+ }
+ cfg->erp = hapd->conf->eap_server_erp;
+
+ return cfg;
+}
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@@ -273,6 +307,14 @@ int authsrv_init(struct hostapd_data *hapd)
}
#endif /* EAP_SIM_DB */
+ hapd->eap_cfg = authsrv_eap_config(hapd);
+ if (!hapd->eap_cfg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to build EAP server configuration");
+ authsrv_deinit(hapd);
+ return -1;
+ }
+
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
@@ -303,4 +345,7 @@ void authsrv_deinit(struct hostapd_data *hapd)
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
+
+ eap_server_config_free(hapd->eap_cfg);
+ hapd->eap_cfg = NULL;
}
diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c
index a51b94960bed..15fc2b3db064 100644
--- a/contrib/wpa/src/ap/beacon.c
+++ b/contrib/wpa/src/ap/beacon.c
@@ -36,27 +36,6 @@
#ifdef NEED_AP_MLME
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
- size_t len)
-{
- size_t i;
-
- for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
- if (hapd->conf->radio_measurements[i])
- break;
- }
-
- if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
- return eid;
-
- *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = RRM_CAPABILITIES_IE_LEN;
- os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
-
- return eid + RRM_CAPABILITIES_IE_LEN;
-}
-
-
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
@@ -287,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+ u32 vendor_type)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
{
const u8 *ie;
- size_t ielen;
- ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
- if (ie == NULL || ielen > len)
- return eid;
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->no_beacon_rsnxe) {
+ wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+ return pos;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
- os_memcpy(eid, ie, ielen);
- return eid + ielen;
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
}
@@ -395,16 +458,20 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ buflen += sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
}
#endif /* CONFIG_IEEE80211AX */
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
+ buflen += hostapd_eid_dpp_cc_len(hapd);
resp = os_zalloc(buflen);
if (resp == NULL)
@@ -455,13 +522,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+ pos = hostapd_get_rsne(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ pos = hostapd_get_mde(hapd, pos, epos - pos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -470,15 +534,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- pos = hostapd_eid_secondary_channel(hapd, pos);
-
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos);
@@ -498,22 +555,34 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
- pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+#endif /* CONFIG_IEEE80211AX */
+
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+
pos = hostapd_eid_fils_indic(hapd, pos, 0);
+ pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
- pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
pos = hostapd_eid_spatial_reuse(hapd, pos);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
+ pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -522,9 +591,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+ /* WPA / OSEN */
+ pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+ pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -553,11 +622,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
- pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+ pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -579,7 +648,9 @@ enum ssid_match_result {
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
const u8 *ssid, size_t ssid_len,
const u8 *ssid_list,
- size_t ssid_list_len)
+ size_t ssid_list_len,
+ const u8 *short_ssid_list,
+ size_t short_ssid_list_len)
{
const u8 *pos, *end;
int wildcard = 0;
@@ -590,20 +661,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
return EXACT_SSID_MATCH;
- if (ssid_list == NULL)
- return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+ if (ssid_list) {
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+ pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+ }
- pos = ssid_list;
- end = ssid_list + ssid_list_len;
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[1] == 0)
- wildcard = 1;
- if (pos[1] == hapd->conf->ssid.ssid_len &&
- os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
- return EXACT_SSID_MATCH;
- pos += 2 + pos[1];
+ if (short_ssid_list) {
+ pos = short_ssid_list;
+ end = short_ssid_list + short_ssid_list_len;
+ while (end - pos >= 4) {
+ if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+ return EXACT_SSID_MATCH;
+ pos += 4;
+ }
}
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -741,11 +822,11 @@ void handle_probe_req(struct hostapd_data *hapd,
int ret;
u16 csa_offs[2];
size_t csa_offs_len;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
+ struct radius_sta rad_info;
+
+ if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
+ ssi_signal < hapd->iconf->rssi_ignore_probe_request)
+ return;
if (len < IEEE80211_HDRLEN)
return;
@@ -754,10 +835,8 @@ void handle_probe_req(struct hostapd_data *hapd,
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
- ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui, 1);
+ ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info, 1);
if (ret == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Probe Request frame from " MACSTR
@@ -836,7 +915,7 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
- elems.ssid_list_len == 0) {
+ elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -868,7 +947,8 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_TAXONOMY */
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
- elems.ssid_list, elems.ssid_list_len);
+ elems.ssid_list, elems.ssid_list_len,
+ elems.short_ssid_list, elems.short_ssid_list_len);
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -881,6 +961,12 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+ "broadcast SSID ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_INTERWORKING
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
@@ -985,9 +1071,9 @@ void handle_probe_req(struct hostapd_data *hapd,
hapd->cs_c_off_ecsa_proberesp;
}
- ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
- csa_offs_len ? csa_offs : NULL,
- csa_offs_len);
+ ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len, 0);
if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -1038,6 +1124,23 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+#ifdef CONFIG_IEEE80211AX
+/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
+static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ return NULL;
+
+ params->unsol_bcast_probe_resp_interval =
+ hapd->conf->unsol_bcast_probe_resp_interval;
+
+ return hostapd_gen_probe_resp(hapd, NULL, 0,
+ &params->unsol_bcast_probe_resp_tmpl_len);
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
void sta_track_del(struct hostapd_sta_info *info)
{
#ifdef CONFIG_TAXONOMY
@@ -1048,6 +1151,243 @@ void sta_track_del(struct hostapd_sta_info *info)
}
+#ifdef CONFIG_FILS
+
+static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
+{
+ u16 cap_info, phy_index = 0;
+ u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+
+ cap_info = FD_CAP_ESS;
+ if (hapd->conf->wpa)
+ cap_info |= FD_CAP_PRIVACY;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ phy_index = FD_CAP_PHY_INDEX_HE;
+
+ switch (hapd->iconf->op_class) {
+ case 135:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case 134:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case 133:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case 132:
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ break;
+ }
+ } else {
+ switch (hostapd_get_oper_chwidth(hapd->iconf)) {
+ case CHANWIDTH_80P80MHZ:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case CHANWIDTH_160MHZ:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case CHANWIDTH_80MHZ:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (hapd->iconf->secondary_channel)
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ else
+ chwidth = FD_CAP_BSS_CHWIDTH_20;
+ break;
+ }
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
+ phy_index = FD_CAP_PHY_INDEX_HE;
+#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211AC
+ if (!phy_index &&
+ hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
+ phy_index = FD_CAP_PHY_INDEX_VHT;
+#endif /* CONFIG_IEEE80211AC */
+ if (!phy_index &&
+ hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
+ phy_index = FD_CAP_PHY_INDEX_HT;
+ }
+
+ cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
+ cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
+
+ if (mode) {
+ u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
+ int i;
+ u16 nss = 0;
+
+ for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
+ u16 nss_mask = 0x3 << (i * 2);
+
+ if (mcs_nss_size == 4 &&
+ (((mcs[0] & nss_mask) == nss_mask) ||
+ ((mcs[1] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 8 &&
+ (((mcs[2] & nss_mask) == nss_mask) ||
+ ((mcs[3] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 12 &&
+ (((mcs[4] & nss_mask) == nss_mask) ||
+ ((mcs[5] & nss_mask) == nss_mask)))
+ continue;
+
+ nss++;
+ }
+
+ if (nss > 4)
+ cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
+ else if (nss)
+ cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
+ }
+
+ return cap_info;
+}
+
+
+static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
+{
+ struct ieee80211_mgmt *head;
+ const u8 *mobility_domain;
+ u8 *pos, *length_pos, buf[200];
+ u16 ctl = 0;
+ u8 fd_rsn_info[5];
+ size_t total_len, buf_len;
+
+ total_len = 24 + 2 + 12;
+
+ /* FILS Discovery Frame Control */
+ ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
+ FD_FRAME_CTL_SHORT_SSID_PRESENT |
+ FD_FRAME_CTL_LENGTH_PRESENT |
+ FD_FRAME_CTL_CAP_PRESENT;
+ total_len += 4 + 1 + 2;
+
+ /* Check for optional subfields and calculate length */
+ if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
+ ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
+ total_len += sizeof(fd_rsn_info);
+ }
+
+ mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (mobility_domain) {
+ ctl |= FD_FRAME_CTL_MD_PRESENT;
+ total_len += 3;
+ }
+
+ pos = hostapd_eid_fils_indic(hapd, buf, 0);
+ buf_len = pos - buf;
+ total_len += buf_len;
+
+ head = os_zalloc(total_len);
+ if (!head)
+ return NULL;
+
+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memset(head->da, 0xff, ETH_ALEN);
+ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+
+ head->u.action.category = WLAN_ACTION_PUBLIC;
+ head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
+
+ pos = &head->u.action.u.public_action.variable[0];
+
+ /* FILS Discovery Information field */
+
+ /* FILS Discovery Frame Control */
+ WPA_PUT_LE16(pos, ctl);
+ pos += 2;
+
+ /* Hardware or low-level driver will fill in the Timestamp value */
+ pos += 8;
+
+ /* Beacon Interval */
+ WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
+ pos += 2;
+
+ /* Short SSID */
+ WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
+ pos += sizeof(hapd->conf->ssid.short_ssid);
+
+ /* Store position of FILS discovery information element Length field */
+ length_pos = pos++;
+
+ /* FD Capability */
+ WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
+ pos += 2;
+
+ /* Operating Class - not present */
+
+ /* Primary Channel - not present */
+
+ /* AP Configuration Sequence Number - not present */
+
+ /* Access Network Options - not present */
+
+ /* FD RSN Information */
+ if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
+ os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
+ pos += sizeof(fd_rsn_info);
+ }
+
+ /* Channel Center Frequency Segment 1 - not present */
+
+ /* Mobility Domain */
+ if (ctl & FD_FRAME_CTL_MD_PRESENT) {
+ os_memcpy(pos, &mobility_domain[2], 3);
+ pos += 3;
+ }
+
+ /* Fill in the Length field value */
+ *length_pos = pos - (length_pos + 1);
+
+ /* FILS Indication element */
+ if (buf_len) {
+ os_memcpy(pos, buf, buf_len);
+ pos += buf_len;
+ }
+
+ *len = pos - (u8 *) head;
+ wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
+ head, pos - (u8 *) head);
+ return (u8 *) head;
+}
+
+
+/* Configure FILS Discovery frame transmission parameters */
+static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ params->fd_max_int = hapd->conf->fils_discovery_max_int;
+ if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+ params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+
+ params->fd_min_int = hapd->conf->fils_discovery_min_int;
+ if (params->fd_min_int > params->fd_max_int)
+ params->fd_min_int = params->fd_max_int;
+
+ if (params->fd_max_int)
+ return hostapd_gen_fils_discovery(hapd,
+ &params->fd_frame_tmpl_len);
+
+ return NULL;
+}
+
+#endif /* CONFIG_FILS */
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -1058,7 +1398,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *csa_pos;
+ u8 *pos, *tailpos, *tailend, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -1087,16 +1427,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
}
#endif /* CONFIG_IEEE80211AX */
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
+ tail_len += hostapd_eid_dpp_cc_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@@ -1105,6 +1449,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
os_free(tail);
return -1;
}
+ tailend = tail + tail_len;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
@@ -1145,8 +1490,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
head_len = pos - (u8 *) head;
- tailpos = hostapd_eid_country(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1163,18 +1507,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
- tailpos = hostapd_eid_wpa(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
+ tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
- tailpos = hostapd_eid_bss_load(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailend - tailpos);
+ tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1183,15 +1520,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = csa_pos;
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
@@ -1214,23 +1544,35 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
- tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AX */
+
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+ tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
- tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
+ tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1239,11 +1581,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA)
- tailpos = hostapd_eid_wpa(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
+ /* WPA / OSEN */
+ tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1271,12 +1611,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
- tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
tail + tail_len - tailpos);
+ tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1315,10 +1655,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
- params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+ params->privacy |= hapd->conf->ssid.wep.keys_set ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
params->hide_ssid = NO_SSID_HIDING;
@@ -1331,7 +1674,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
break;
}
params->isolate = hapd->conf->isolate;
- params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
@@ -1390,6 +1732,14 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
+#ifdef CONFIG_FILS
+ os_free(params->fd_frame_tmpl);
+ params->fd_frame_tmpl = NULL;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ os_free(params->unsol_bcast_probe_resp_tmpl);
+ params->unsol_bcast_probe_resp_tmpl = NULL;
+#endif /* CONFIG_IEEE80211AX */
}
@@ -1403,6 +1753,11 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
+ if (!hapd->drv_priv) {
+ wpa_printf(MSG_ERROR, "Interface is disabled");
+ return -1;
+ }
+
if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
return -1;
@@ -1421,11 +1776,41 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
+#ifdef CONFIG_IEEE80211AX
+ params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
+ params.he_spr_non_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
+ params.he_spr_srg_obss_pd_min_offset =
+ hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ params.he_spr_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(params.he_spr_bss_color_bitmap,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ os_memcpy(params.he_spr_partial_bssid_bitmap,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
+ params.he_bss_color_disabled =
+ hapd->iface->conf->he_op.he_bss_color_disabled;
+ params.he_bss_color_partial =
+ hapd->iface->conf->he_op.he_bss_color_partial;
+ params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+ params.twt_responder = hostapd_get_he_twt_responder(hapd,
+ IEEE80211_MODE_AP);
+ params.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, &params);
+#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
+#ifdef CONFIG_SAE
+ params.sae_pwe = hapd->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
+#endif /* CONFIG_FILS */
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
- iconf->channel, iconf->ieee80211n,
+ iconf->channel, iconf->enable_edmg,
+ iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),
diff --git a/contrib/wpa/src/ap/beacon.h b/contrib/wpa/src/ap/beacon.h
index a26e30879cf5..c320825f3570 100644
--- a/contrib/wpa/src/ap/beacon.h
+++ b/contrib/wpa/src/ap/beacon.h
@@ -30,4 +30,6 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
struct wpabuf **probe_ie_taxonomy);
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+
#endif /* BEACON_H */
diff --git a/contrib/wpa/src/ap/ctrl_iface_ap.c b/contrib/wpa/src/ap/ctrl_iface_ap.c
index 2c4953d8bbcb..28e40ba9cede 100644
--- a/contrib/wpa/src/ap/ctrl_iface_ap.c
+++ b/contrib/wpa/src/ap/ctrl_iface_ap.c
@@ -273,6 +273,36 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
+
+ if (sta->sae && sta->sae->tmp) {
+ const u8 *pos;
+ unsigned int j, count;
+ struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
+
+ res = os_snprintf(buf + len, buflen - len,
+ "sae_rejected_groups=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+
+ if (groups) {
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ } else {
+ pos = NULL;
+ count = 0;
+ }
+ for (j = 0; pos && j < count; j++) {
+ res = os_snprintf(buf + len, buflen - len, "%s%d",
+ j == 0 ? "" : " ", WPA_GET_LE16(pos));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ pos += 2;
+ }
+
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
#endif /* CONFIG_SAE */
if (sta->vlan_id > 0) {
@@ -315,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
"ht_caps_info=0x%04x\n",
@@ -324,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
-#endif /* CONFIG_IEEE80211N */
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
@@ -432,9 +460,6 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
-
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
@@ -468,8 +493,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
pos += 2;
*pos++ = minor_reason_code;
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
+ ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
+ 0);
os_free(mgmt);
return ret < 0 ? -1 : 0;
@@ -499,8 +524,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -510,10 +534,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -562,8 +586,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -573,10 +596,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -709,6 +732,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
+ "edmg_enable=%d\n"
+ "edmg_channel=%d\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
@@ -716,17 +741,36 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
iface->conf->secondary_channel : 0,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
- iface->conf->ieee80211ax,
+ iface->conf->ieee80211ax &&
+ !hapd->conf->disable_11ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "he_oper_chwidth=%d\n"
+ "he_oper_centr_freq_seg0_idx=%d\n"
+ "he_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->he_oper_chwidth,
+ iface->conf->he_oper_centr_freq_seg0_idx,
+ iface->conf->he_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
@@ -865,6 +909,7 @@ int hostapd_parse_csa_settings(const char *pos,
SET_CSA_SETTING(sec_channel_offset);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+ settings->freq_params.he_enabled = !!os_strstr(pos, " he");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
diff --git a/contrib/wpa/src/ap/dfs.c b/contrib/wpa/src/ap/dfs.c
index ac23c2b1bc9f..03c99b175215 100644
--- a/contrib/wpa/src/ap/dfs.c
+++ b/contrib/wpa/src/ap/dfs.c
@@ -81,17 +81,17 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
* We will also choose this first channel as the control one.
*/
int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
+ 165, 173, 184, 192 };
/*
* VHT80, valid channels based on center frequency:
- * 42, 58, 106, 122, 138, 155
+ * 42, 58, 106, 122, 138, 155, 171
*/
- int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+ int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
/*
* VHT160 valid channels based on center frequency:
- * 50, 114
+ * 50, 114, 163
*/
- int allowed_160[] = { 36, 100 };
+ int allowed_160[] = { 36, 100, 149 };
int *allowed = allowed_40;
unsigned int i, allowed_no = 0;
@@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int i;
u32 bw = num_chan_to_bw(num_chans);
- if (first_chan_idx + num_chans > mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: some channels in range not defined");
return 0;
+ }
first_chan = &mode->channels[first_chan_idx];
/* hostapd DFS implementation assumes the first channel as primary.
* If it's not allowed to use the first channel as primary, decline the
* whole channel range. */
- if (!chan_pri_allowed(first_chan))
+ if (!chan_pri_allowed(first_chan)) {
+ wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
return 0;
+ }
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
- if (!chan)
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
/* HT 40 MHz secondary channel availability checked only for
* primary channel */
- if (!chan_bw_allowed(chan, bw, 1, !i))
+ if (!chan_bw_allowed(chan, bw, 1, !i)) {
+ wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
- if (!dfs_channel_available(chan, skip_radar))
+ if (!dfs_channel_available(chan, skip_radar)) {
+ wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+ first_chan->freq + i * 20);
return 0;
+ }
}
return 1;
@@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) ||
- !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) is incompatible",
+ chan->freq, chan->chan);
continue;
+ }
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: range not available for %d (%d)",
+ chan->freq, chan->chan);
continue;
+ }
- if (!is_in_chanlist(iface, chan))
+ if (!is_in_chanlist(iface, chan)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) not in chanlist",
+ chan->freq, chan->chan);
continue;
+ }
if (ret_chan && idx == channel_idx) {
- wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
+ chan->freq, chan->chan);
*ret_chan = chan;
return idx;
}
- wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
+ chan->freq, chan->chan);
channel_idx++;
}
return channel_idx;
@@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
+ int sec_chan_idx_80p80,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx)
{
@@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
+ case CHANWIDTH_80P80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
+ *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
+ break;
+
default:
- wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+ wpa_printf(MSG_INFO,
+ "DFS: Unsupported channel width configuration");
*oper_centr_freq_seg0_idx = 0;
break;
}
@@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
+ struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs;
- int chan_idx;
+ int chan_idx, chan_idx2;
+ int sec_chan_idx_80p80 = -1;
+ int i;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+ num_available_chandefs);
if (num_available_chandefs == 0)
return NULL;
@@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
+ chan->freq, chan->chan);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else
*secondary_channel = 0;
+ /* Get secondary channel for HT80P80 */
+ if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+ if (num_available_chandefs <= 1) {
+ wpa_printf(MSG_ERROR,
+ "only 1 valid chan, can't support 80+80");
+ return NULL;
+ }
+
+ /*
+ * Loop all channels except channel1 to find a valid channel2
+ * that is not adjacent to channel1.
+ */
+ for (i = 0; i < num_available_chandefs - 1; i++) {
+ /* start from chan_idx + 1, end when chan_idx - 1 */
+ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+ dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+ /* two channels are not adjacent */
+ sec_chan_idx_80p80 = chan2->chan;
+ wpa_printf(MSG_DEBUG,
+ "DFS: got second chan: %d (%d)",
+ chan2->freq, chan2->chan);
+ break;
+ }
+ }
+
+ /* Check if we got a valid secondary channel which is not
+ * adjacent to the first channel.
+ */
+ if (sec_chan_idx_80p80 == -1) {
+ wpa_printf(MSG_INFO,
+ "DFS: failed to get chan2 for 80+80");
+ return NULL;
+ }
+ }
+
dfs_adjust_center_freq(iface, chan,
*secondary_channel,
+ sec_chan_idx_80p80,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
@@ -515,6 +598,7 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
int n_chans = 1, i;
struct hostapd_hw_modes *mode;
int frequency = freq;
+ int frequency2 = 0;
int ret = 0;
mode = iface->current_mode;
@@ -542,6 +626,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
n_chans = 4;
frequency = cf1 - 30;
break;
+ case CHAN_WIDTH_80P80:
+ n_chans = 4;
+ frequency = cf1 - 30;
+ frequency2 = cf2 - 30;
+ break;
case CHAN_WIDTH_160:
n_chans = 8;
frequency = cf1 - 70;
@@ -557,6 +646,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
for (i = 0; i < n_chans; i++) {
ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
+
+ if (chan_width == CHAN_WIDTH_80P80) {
+ ret += set_dfs_state_freq(iface, frequency2, state);
+ frequency2 = frequency2 + 20;
+ }
}
return ret;
@@ -662,6 +756,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
+ if (is_6ghz_freq(iface->freq))
+ return 1;
+
if (!iface->current_mode) {
/*
* This can happen with drivers that do not provide mode
@@ -759,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
}
-static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
@@ -807,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
* another radio.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
- hostapd_config_dfs_chan_available(iface)) {
+ hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 0;
}
@@ -837,6 +934,44 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
}
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+{
+ struct hostapd_channel_data *channel;
+
+ for (;;) {
+ channel = dfs_get_valid_channel(iface, secondary_channel,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ *skip_radar);
+ if (channel) {
+ wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
+ channel->chan);
+ return channel;
+ }
+
+ if (*skip_radar) {
+ *skip_radar = 0;
+ } else {
+ int oper_chwidth;
+
+ oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ if (oper_chwidth == CHANWIDTH_USE_HT)
+ break;
+ *skip_radar = 1;
+ hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
+ return NULL;
+}
+
+
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -854,8 +989,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
- wpa_printf(MSG_ERROR, "No valid channel available");
- return err;
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ return err;
+ }
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -884,11 +1025,14 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
+ u8 new_vht_oper_chwidth;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -922,28 +1066,33 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* requires to perform a CAC first.
*/
skip_radar = 0;
- channel = dfs_get_valid_channel(iface, &secondary_channel,
- &oper_centr_freq_seg0_idx,
- &oper_centr_freq_seg1_idx,
- skip_radar);
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
if (!channel) {
- wpa_printf(MSG_INFO,
- "%s: no DFS channels left, waiting for NOP to finish",
- __func__);
- return err;
+ /*
+ * Toggle interface state to enter DFS state
+ * until NOP is finished.
+ */
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
}
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
- oper_centr_freq_seg0_idx);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
- oper_centr_freq_seg1_idx);
-
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
- return 0;
+ if (!skip_radar) {
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ iface->conf, oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, oper_centr_freq_seg1_idx);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+ }
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -952,23 +1101,32 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
+
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
csa_settings.block_tx = 1;
+#ifdef CONFIG_MESH
+ if (iface->mconf)
+ ieee80211_mode = IEEE80211_MODE_MESH;
+#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
channel->freq,
channel->chan,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
secondary_channel,
- hostapd_get_oper_chwidth(iface->conf),
+ new_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP]);
+ &cmode->he_capab[ieee80211_mode]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -988,6 +1146,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
@@ -1024,8 +1183,10 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
return 0;
/* mark radar frequency as invalid */
- set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ if (!res)
+ return 0;
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -1067,7 +1228,9 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
- if (!iface->conf->ieee80211h || !iface->current_mode ||
+ if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ !iface->conf->ieee80211h) ||
+ !iface->current_mode ||
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
@@ -1093,11 +1256,18 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
+ /* This is called when the driver indicates that an offloaded DFS has
+ * started CAC. */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ /* TODO: How to check CAC time for ETSI weather channels? */
+ iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
- freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
+ iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
+ os_get_reltime(&iface->dfs_cac_start);
return 0;
}
@@ -1111,6 +1281,8 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
*/
int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
{
+ int dfs_res;
+
wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
__func__, iface->cac_started);
@@ -1126,10 +1298,11 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
return 1;
}
- if (ieee80211_is_dfs(iface->freq, iface->hw_features,
- iface->num_hw_features)) {
- wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
- __func__, iface->freq);
+ dfs_res = hostapd_is_dfs_required(iface);
+ if (dfs_res > 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: freq %d MHz requires DFS for %d chans",
+ __func__, iface->freq, dfs_res);
return 0;
}
@@ -1138,3 +1311,60 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
__func__, iface->freq);
return 2;
}
+
+
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq)
+{
+ struct hostapd_channel_data *chan;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int half_width;
+ int res = 0;
+ int i;
+
+ if (!iface->conf->ieee80211h || !mode ||
+ mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ half_width = 10;
+ break;
+ case CHAN_WIDTH_40:
+ half_width = 20;
+ break;
+ case CHAN_WIDTH_80:
+ case CHAN_WIDTH_80P80:
+ half_width = 40;
+ break;
+ case CHAN_WIDTH_160:
+ half_width = 80;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
+ width);
+ return 0;
+ }
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+
+ if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_AVAILABLE)
+ continue;
+
+ if (center_freq - chan->freq < half_width &&
+ chan->freq - center_freq < half_width)
+ res++;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
+ center_freq - half_width, center_freq + half_width,
+ res ? "yes" : "no");
+
+ return res;
+}
diff --git a/contrib/wpa/src/ap/dfs.h b/contrib/wpa/src/ap/dfs.h
index f0fa6f688037..606c1b39399f 100644
--- a/contrib/wpa/src/ap/dfs.h
+++ b/contrib/wpa/src/ap/dfs.h
@@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq);
#endif /* DFS_H */
diff --git a/contrib/wpa/src/ap/dhcp_snoop.c b/contrib/wpa/src/ap/dhcp_snoop.c
index ed37fc8fe96a..edc77da2e797 100644
--- a/contrib/wpa/src/ap/dhcp_snoop.c
+++ b/contrib/wpa/src/ap/dhcp_snoop.c
@@ -39,22 +39,22 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
- u16 tot_len;
+ u16 ip_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
- tot_len = ntohs(b->iph.tot_len);
- if (tot_len > (unsigned int) (len - ETH_HLEN))
+ ip_len = ntohs(b->iph.ip_len);
+ if (ip_len > (unsigned int) (len - ETH_HLEN))
return;
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
- end = (const u8 *) b + tot_len;
+ end = (const u8 *) b + ip_len;
pos = &b->exten[4];
while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
diff --git a/contrib/wpa/src/ap/dpp_hostapd.c b/contrib/wpa/src/ap/dpp_hostapd.c
index 697c3bad34ab..93ffd8cf7c36 100644
--- a/contrib/wpa/src/ap/dpp_hostapd.c
+++ b/contrib/wpa/src/ap/dpp_hostapd.c
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,9 +23,18 @@
static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
+#ifdef CONFIG_DPP2
+static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf);
+#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -58,10 +68,97 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
wpabuf_len(hapd->dpp_auth->resp_msg));
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(hapd->iface->interfaces->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
+ return bi->id;
+}
+
+
+/**
+ * hostapd_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @hapd: Pointer to hostapd_data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, cmd);
+ if (!bi)
+ return -1;
+
return bi->id;
}
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -151,8 +248,14 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+#endif /* CONFIG_DPP2 */
hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -178,6 +281,17 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
}
}
+ if (auth->waiting_auth_conf &&
+ auth->auth_resp_status == DPP_STATUS_OK) {
+ /* Make sure we do not get stuck waiting for Auth Confirm
+ * indefinitely after successfully transmitted Auth Response to
+ * allow new authentication exchanges to be started. */
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd,
+ NULL);
+ eloop_register_timeout(1, 0, hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
+ }
+
if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
/* Allow timeout handling to stop iteration if no response is
* received from a peer that has ACKed a request. */
@@ -278,6 +392,25 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_auth_conf)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No Auth Confirm received");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth)
{
@@ -362,7 +495,9 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
freq = auth->freq[auth->freq_idx++];
auth->curr_freq = freq;
- if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ if (!is_zero_ether_addr(auth->peer_mac_addr))
+ dst = auth->peer_mac_addr;
+ else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
dst = broadcast;
else
dst = auth->peer_bi->mac_addr;
@@ -394,12 +529,35 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
}
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct hostapd_data *hapd = ctx;
+ unsigned int i;
+
+ for (i = 0; i < auth->num_conf_obj; i++)
+ hostapd_dpp_handle_config_obj(hapd, auth,
+ &auth->conf_obj[i]);
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -412,6 +570,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
@@ -449,36 +626,48 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
if (pos)
neg_freq = atoi(pos + 10);
- if (hapd->dpp_auth) {
+ if (!tcp && hapd->dpp_auth) {
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+#endif /* CONFIG_DPP2 */
hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
- allowed_roles, neg_freq,
- hapd->iface->hw_features,
- hapd->iface->num_hw_features);
- if (!hapd->dpp_auth)
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, own_bi, allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!auth)
goto fail;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth, cmd) < 0) {
- dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = NULL;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
goto fail;
}
- hapd->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
+ &ipaddr, tcp_port, hapd->conf->dpp_name,
+ DPP_NETROLE_AP, hapd->msg_ctx, hapd,
+ hostapd_dpp_process_conf_obj);
+#endif /* CONFIG_DPP2 */
+
+ hapd->dpp_auth = auth;
return hostapd_dpp_auth_init_next(hapd);
fail:
return -1;
@@ -510,12 +699,14 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+ hostapd_drv_dpp_listen(hapd, true);
return 0;
}
void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
{
+ hostapd_drv_dpp_listen(hapd, false);
/* TODO: Stop listen operation on non-operating channel */
}
@@ -534,6 +725,10 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ hostapd_dpp_chirp_stop(hapd);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -562,7 +757,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
if (!own_bi) {
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
src, hdr, buf, len, freq, i_bootstrap,
- r_bootstrap) == 0)
+ r_bootstrap, hapd) == 0)
return;
}
#endif /* CONFIG_DPP2 */
@@ -579,7 +774,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
}
hapd->dpp_auth_ok_on_ack = 0;
- hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+ hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, hapd->dpp_allowed_roles,
hapd->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) {
@@ -587,8 +783,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth,
+ if (dpp_set_configurator(hapd->dpp_auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -607,47 +802,49 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
- dpp_akm_str(auth->akm));
- if (auth->ssid_len)
+ dpp_akm_str(conf->akm));
+ if (conf->ssid_len)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
- } else if (auth->passphrase[0]) {
+ conf->connector);
+ }
+ if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
- (const u8 *) auth->passphrase,
- os_strlen(auth->passphrase));
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
hex);
- } else if (auth->psk_set) {
+ } else if (conf->psk_set) {
char hex[PMK_LEN * 2 + 1];
- wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
hex);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(hapd->msg_ctx, MSG_INFO,
DPP_EVENT_C_SIGN_KEY "%s", hex);
os_free(hex);
@@ -677,6 +874,33 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
}
+static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(
+ hapd->iface->interfaces->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result,
const struct wpabuf *adv_proto,
@@ -691,7 +915,8 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
- if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ if (result != GAS_QUERY_AP_SUCCESS ||
+ !resp || status_code != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
goto fail;
}
@@ -720,7 +945,10 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
+ if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0)
+ goto fail;
+
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -765,18 +993,11 @@ static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
- int netrole_ap = 1;
-
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name,
+ DPP_NETROLE_AP,
+ hapd->conf->dpp_mud_url, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -922,6 +1143,24 @@ static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
}
+static void hostapd_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -945,6 +1184,21 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(
+ hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(
+ 16, 0, hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ return;
+ }
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
@@ -957,6 +1211,263 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
NULL);
}
+
+static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+}
+
+
+static void
+hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
+ r_bootstrap);
+ dpp_notify_chirp_received(hapd->msg_ctx,
+ peer_bi ? (int) peer_bi->id : -1,
+ src, freq, r_bootstrap);
+ if (!peer_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ r_bootstrap, hapd) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
+ 0);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ /* The source address of the Presence Announcement frame overrides any
+ * MAC address information from the bootstrapping information. */
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+
+ hapd->dpp_auth = auth;
+ if (hostapd_dpp_auth_init_next(hapd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
+
+static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+static void
+hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
+ struct dpp_configurator *conf;
+ struct dpp_authentication *auth;
+ unsigned int wait_time, max_wait_time;
+ u16 group;
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
+ MAC2STR(src));
+
+ csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+ &csign_hash_len);
+ if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Configurator C-sign key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+ csign_hash, csign_hash_len);
+ conf = dpp_configurator_find_kid(hapd->iface->interfaces->dpp,
+ csign_hash);
+ if (!conf) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ NULL, hapd) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching Configurator information found");
+ return;
+ }
+
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ conf, freq, group, a_nonce, a_nonce_len,
+ e_id, e_id_len);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ hapd->dpp_auth = auth;
+
+ hapd->dpp_in_response_listen = 0;
+ hapd->dpp_auth_ok_on_ack = 0;
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+ max_wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+ wait_time -= 10;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
+ if (hostapd_drv_send_action(hapd, freq, wait_time, src,
+ wpabuf_head(auth->reconfig_req_msg),
+ wpabuf_len(auth->reconfig_req_msg)) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
+
+static void
+hostapd_dpp_rx_reconfig_auth_resp(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ struct wpabuf *conf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || !auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+ if (!conf)
+ return;
+
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
+ if (hostapd_drv_send_action(hapd, freq, 500, src,
+ wpabuf_head(conf), wpabuf_len(conf)) < 0) {
+ wpabuf_free(conf);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+ wpabuf_free(conf);
+}
+
#endif /* CONFIG_DPP2 */
@@ -966,9 +1477,13 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
enum dpp_status_error status)
{
struct wpabuf *msg;
+ size_t len;
- msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
- 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
+ len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
+#ifdef CONFIG_DPP2
+ len += 5;
+#endif /* CONFIG_DPP2 */
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, len);
if (!msg)
return;
@@ -1041,6 +1556,15 @@ skip_status:
skip_connector:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1) {
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
" status=%d", MAC2STR(src), status);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
@@ -1368,7 +1892,8 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
#ifdef CONFIG_DPP2
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
- src, hdr, buf, len, freq, NULL, NULL) == 0)
+ src, hdr, buf, len, freq, NULL, NULL,
+ hapd) == 0)
return;
#endif /* CONFIG_DPP2 */
@@ -1403,6 +1928,21 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
case DPP_PA_CONFIGURATION_RESULT:
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
+ break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_ANNOUNCEMENT:
+ hostapd_dpp_rx_reconfig_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ hostapd_dpp_rx_reconfig_auth_resp(hapd, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1432,7 +1972,7 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
- if (!auth || !auth->auth_success ||
+ if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
#ifdef CONFIG_DPP2
if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
@@ -1444,6 +1984,19 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
+
+ if (hapd->dpp_auth_ok_on_ack && auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
+ /* hostapd_dpp_auth_success() would normally have been called
+ * from TX status handler, but since there was no such handler
+ * call yet, simply send out the event message and proceed with
+ * exchange. */
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_AUTH_SUCCESS "init=1");
+ hapd->dpp_auth_ok_on_ack = 0;
+ }
+
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
@@ -1466,8 +2019,11 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
@@ -1497,16 +2053,15 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
hostapd_dpp_set_testing_options(hapd, auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
}
@@ -1710,11 +2265,17 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
if (!hapd->dpp_init_done)
return;
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
+ NULL);
+ hostapd_dpp_chirp_stop(hapd);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -1723,3 +2284,359 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = NULL;
}
+
+
+#ifdef CONFIG_DPP2
+
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_controller_config config;
+ const char *pos;
+
+ os_memset(&config, 0, sizeof(config));
+ config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_AP;
+ config.msg_ctx = hapd->msg_ctx;
+ config.cb_ctx = hapd;
+ config.process_conf_obj = hostapd_dpp_process_conf_obj;
+ if (cmd) {
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ config.tcp_port = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ config.allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ return -1;
+ }
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+ }
+ config.configurator_params = hapd->dpp_configurator_params;
+ return dpp_controller_start(hapd->iface->interfaces->dpp, &config);
+}
+
+
+static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_chirp_next(hapd, NULL);
+}
+
+
+static void hostapd_dpp_chirp_start(struct hostapd_data *hapd)
+{
+ struct wpabuf *msg;
+ int type;
+
+ msg = hapd->dpp_presence_announcement;
+ type = DPP_PA_PRESENCE_ANNOUNCEMENT;
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", hapd->dpp_chirp_freq);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(broadcast), hapd->dpp_chirp_freq, type);
+ if (hostapd_drv_send_action(
+ hapd, hapd->dpp_chirp_freq, 2000, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg)) < 0 ||
+ eloop_register_timeout(2, 0, hostapd_dpp_chirp_timeout,
+ hapd, NULL) < 0)
+ hostapd_dpp_chirp_stop(hapd);
+}
+
+
+static struct hostapd_hw_modes *
+dpp_get_mode(struct hostapd_data *hapd,
+ enum hostapd_hw_mode mode)
+{
+ struct hostapd_hw_modes *modes = hapd->iface->hw_features;
+ u16 num_modes = hapd->iface->num_hw_features;
+ u16 i;
+
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ return &modes[i];
+ }
+
+ return NULL;
+}
+
+
+static void
+hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct wpa_scan_results *scan_res;
+ struct dpp_bootstrap_info *bi = hapd->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+
+ if (!bi)
+ return;
+
+ hapd->dpp_chirp_scan_done = 1;
+
+ scan_res = hostapd_driver_get_scan_results(hapd);
+
+ os_free(hapd->dpp_chirp_freqs);
+ hapd->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ if (bi) {
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&hapd->dpp_chirp_freqs,
+ bi->freq[i]);
+ }
+
+ /* Preferred chirping channels */
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 2437);
+
+ mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211A);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 5220);
+ }
+
+ mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211AD);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ for (i = 0; scan_res && i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ size_t ie_len = bss->ie_len;
+
+ if (!ie_len)
+ ie_len = bss->beacon_ie_len;
+ if (get_vendor_ie((const u8 *) (bss + 1), ie_len,
+ DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&hapd->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!hapd->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, hostapd_dpp_chirp_next,
+ hapd, NULL) < 0)
+ hostapd_dpp_chirp_stop(hapd);
+
+ wpa_scan_results_free(scan_res);
+}
+
+
+static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ int i;
+
+ if (hapd->dpp_chirp_listen)
+ hostapd_dpp_listen_stop(hapd);
+
+ if (hapd->dpp_chirp_freq == 0) {
+ if (hapd->dpp_chirp_round % 4 == 0 &&
+ !hapd->dpp_chirp_scan_done) {
+ struct wpa_driver_scan_params params;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ os_memset(&params, 0, sizeof(params));
+ ret = hostapd_driver_scan(hapd, &params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to request a scan ret=%d (%s)",
+ ret, strerror(-ret));
+ hostapd_dpp_chirp_scan_res_handler(hapd->iface);
+ } else {
+ hapd->iface->scan_cb =
+ hostapd_dpp_chirp_scan_res_handler;
+ }
+ return;
+ }
+ hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[0];
+ hapd->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ hapd->dpp_chirp_round);
+ } else {
+ for (i = 0; hapd->dpp_chirp_freqs[i]; i++)
+ if (hapd->dpp_chirp_freqs[i] == hapd->dpp_chirp_freq)
+ break;
+ if (!hapd->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ hapd->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (hapd->dpp_chirp_freqs[i]) {
+ hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[i];
+ } else {
+ hapd->dpp_chirp_iter--;
+ if (hapd->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ hostapd_dpp_chirp_stop(hapd);
+ return;
+ }
+ hapd->dpp_chirp_freq = 0;
+ hapd->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0,
+ hostapd_dpp_chirp_next,
+ hapd, NULL) < 0) {
+ hostapd_dpp_chirp_stop(hapd);
+ return;
+ }
+ if (hapd->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ hapd->dpp_chirp_listen);
+ /* TODO: start listen on the channel */
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ hostapd_dpp_chirp_start(hapd);
+}
+
+
+int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (listen_freq <= 0)
+ return -1;
+ }
+
+ hostapd_dpp_chirp_stop(hapd);
+ hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ hapd->dpp_qr_mutual = 0;
+ hapd->dpp_chirp_bi = bi;
+ hapd->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!hapd->dpp_presence_announcement)
+ return -1;
+ hapd->dpp_chirp_iter = iter;
+ hapd->dpp_chirp_round = 0;
+ hapd->dpp_chirp_scan_done = 0;
+ hapd->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, hostapd_dpp_chirp_next, hapd, NULL);
+}
+
+
+void hostapd_dpp_chirp_stop(struct hostapd_data *hapd)
+{
+ if (hapd->dpp_presence_announcement) {
+ hostapd_drv_send_action_cancel_wait(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ hapd->dpp_chirp_bi = NULL;
+ wpabuf_free(hapd->dpp_presence_announcement);
+ hapd->dpp_presence_announcement = NULL;
+ if (hapd->dpp_chirp_listen)
+ hostapd_dpp_listen_stop(hapd);
+ hapd->dpp_chirp_listen = 0;
+ hapd->dpp_chirp_freq = 0;
+ os_free(hapd->dpp_chirp_freqs);
+ hapd->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(hostapd_dpp_chirp_next, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_chirp_timeout, hapd, NULL);
+ if (hapd->iface->scan_cb == hostapd_dpp_chirp_scan_res_handler) {
+ /* TODO: abort ongoing scan */
+ hapd->iface->scan_cb = NULL;
+ }
+}
+
+
+static int handle_dpp_remove_bi(struct hostapd_iface *iface, void *ctx)
+{
+ struct dpp_bootstrap_info *bi = ctx;
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+
+ if (bi == hapd->dpp_chirp_bi)
+ hostapd_dpp_chirp_stop(hapd);
+ }
+
+ return 0;
+}
+
+
+void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+ struct hapd_interfaces *interfaces = ctx;
+
+ hostapd_for_each_interface(interfaces, handle_dpp_remove_bi, bi);
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/ap/dpp_hostapd.h b/contrib/wpa/src/ap/dpp_hostapd.h
index c1ec5d70e411..264d3e4c0166 100644
--- a/contrib/wpa/src/ap/dpp_hostapd.h
+++ b/contrib/wpa/src/ap/dpp_hostapd.h
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +10,12 @@
#ifndef DPP_HOSTAPD_H
#define DPP_HOSTAPD_H
+struct dpp_bootstrap_info;
+
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
@@ -35,4 +41,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd);
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
+void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
+
#endif /* DPP_HOSTAPD_H */
diff --git a/contrib/wpa/src/ap/drv_callbacks.c b/contrib/wpa/src/ap/drv_callbacks.c
index 31587685fe3b..ec5abf166b23 100644
--- a/contrib/wpa/src/ap/drv_callbacks.c
+++ b/contrib/wpa/src/ap/drv_callbacks.c
@@ -16,6 +16,8 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
+#include "common/sae.h"
+#include "common/hw_features_common.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -103,20 +105,45 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
+static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
- int new_assoc, res;
+ int new_assoc;
+ enum wpa_validate_result res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
- u16 status = WLAN_STATUS_SUCCESS;
+ int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
@@ -131,6 +158,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
"hostapd_notif_assoc: Skip event with no address");
return -1;
}
+
+ if (is_multicast_ether_addr(addr) ||
+ is_zero_ether_addr(addr) ||
+ os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR
+ " in received indication - ignore this indication silently",
+ __func__, MAC2STR(addr));
+ return 0;
+ }
+
random_add_randomness(addr, ETH_ALEN);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -207,7 +247,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab &
@@ -221,7 +260,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -281,6 +319,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
+ if (check_sa_query_need(hapd, sta)) {
+ 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);
+ return 0;
+ }
+
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
@@ -308,58 +357,75 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
ie, ielen,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
- if (res != WPA_IE_OK) {
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ switch (res) {
+ case WPA_IE_OK:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_SUCCESS;
+ break;
+ case WPA_INVALID_IE:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_GROUP:
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_PAIRWISE:
+ reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_AKMP:
+ reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ break;
+ case WPA_NOT_ENABLED:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_ALLOC_FAIL:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ break;
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ break;
+ case WPA_INVALID_MDIE:
+ reason = WLAN_REASON_INVALID_MDE;
+ status = WLAN_STATUS_INVALID_MDIE;
+ break;
+ case WPA_INVALID_PROTO:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_PMKID:
+ reason = WLAN_REASON_INVALID_PMKID;
+ status = WLAN_STATUS_INVALID_PMKID;
+ break;
+ case WPA_DENIED_OTHER_REASON:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ break;
+ }
+ if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_PAIRWISE) {
- reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_AKMP) {
- reason = WLAN_REASON_AKMP_NOT_VALID;
- status = WLAN_STATUS_AKMP_NOT_VALID;
- }
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
- reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
- status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- }
-#endif /* CONFIG_IEEE80211W */
- else {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- }
goto fail;
}
-#ifdef CONFIG_IEEE80211W
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
+ if (check_sa_query_need(hapd, sta)) {
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
@@ -373,7 +439,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -390,6 +455,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && !sta->sae->h2e &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SAE_H2E)) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+#endif /* CONFIG_SAE */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -442,6 +521,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -453,13 +535,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_MBO */
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
- sta->auth_alg, req_ies, req_ies_len);
+ sta->auth_alg, req_ies, req_ies_len,
+ !elems.rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -546,22 +625,24 @@ skip_wpa_check:
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
elems.owe_dh) {
u8 *npos;
+ u16 ret_status;
npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf),
- &reason);
+ &ret_status);
+ status = ret_status;
if (npos)
p = npos;
+
if (!npos &&
- reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
- status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
p - buf);
return 0;
}
- if (!npos || reason != WLAN_STATUS_SUCCESS)
+ if (!npos || status != WLAN_STATUS_SUCCESS)
goto fail;
}
#endif /* CONFIG_OWE */
@@ -598,6 +679,11 @@ skip_wpa_check:
pfs_fail:
#endif /* CONFIG_DPP2 */
+ if (elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@@ -644,7 +730,8 @@ skip_wpa_check:
fail:
#ifdef CONFIG_IEEE80211R_AP
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+ if (status >= 0)
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
@@ -682,6 +769,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -775,8 +863,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
int finished)
{
- /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
-
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
@@ -784,9 +870,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
- freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+ freq, ht, hapd->iconf->ch_switch_vht_config,
+ hapd->iconf->ch_switch_he_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@@ -826,9 +913,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
- if (cf1 > 5000)
+ if (cf1 == 5935)
+ seg0_idx = (cf1 - 5925) / 5;
+ else if (cf1 > 5950)
+ seg0_idx = (cf1 - 5950) / 5;
+ else if (cf1 > 5000)
seg0_idx = (cf1 - 5000) / 5;
- if (cf2 > 5000)
+
+ if (cf2 == 5935)
+ seg1_idx = (cf2 - 5925) / 5;
+ else if (cf2 > 5950)
+ seg1_idx = (cf2 - 5950) / 5;
+ else if (cf2 > 5000)
seg1_idx = (cf2 - 5000) / 5;
break;
default:
@@ -849,13 +945,31 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
else if (hapd->iconf->ch_switch_vht_config &
CH_SWITCH_VHT_DISABLED)
hapd->iconf->ieee80211ac = 0;
+ } else if (hapd->iconf->ch_switch_he_config) {
+ /* CHAN_SWITCH HE config */
+ if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_ENABLED)
+ hapd->iconf->ieee80211ax = 1;
+ else if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_DISABLED)
+ hapd->iconf->ieee80211ax = 0;
}
hapd->iconf->ch_switch_vht_config = 0;
+ hapd->iconf->ch_switch_he_config = 0;
hapd->iconf->secondary_channel = offset;
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
+ if (hapd->iconf->ieee80211ac) {
+ hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ if (chwidth == CHANWIDTH_160MHZ)
+ hapd->iconf->vht_capab |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ else if (chwidth == CHANWIDTH_80P80MHZ)
+ hapd->iconf->vht_capab |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ }
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
hapd->iface->num_hw_features);
@@ -879,10 +993,39 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ } else if (is_dfs &&
+ hostapd_is_dfs_required(hapd->iface) &&
+ !hostapd_is_dfs_chan_available(hapd->iface) &&
+ !hapd->iface->cac_started) {
+ hostapd_disable_iface(hapd->iface);
+ hostapd_enable_iface(hapd->iface);
}
for (i = 0; i < hapd->iface->num_bss; i++)
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
+
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv) {
+ struct sta_info *sta;
+ bool check_sa_query = false;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
+ sta->post_csa_sa_query = 1;
+ check_sa_query = true;
+ }
+ }
+
+ if (check_sa_query) {
+ wpa_printf(MSG_DEBUG,
+ "OCV: Check post-CSA SA Query initiation in 15 seconds");
+ eloop_register_timeout(15, 0,
+ hostapd_ocv_check_csa_sa_query,
+ hapd, NULL);
+ }
+ }
+#endif /* CONFIG_OCV */
#endif /* NEED_AP_MLME */
}
@@ -909,6 +1052,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
{
int ret, i;
int err = 0;
+ struct hostapd_channel_data *pri_chan;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -916,12 +1060,20 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
return;
}
+ hapd->iface->freq = acs_res->pri_freq;
+
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];
if (mode->mode == acs_res->hw_mode) {
+ if (hapd->iface->freq > 0 &&
+ !hw_get_chan(mode->mode,
+ hapd->iface->freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features))
+ continue;
hapd->iface->current_mode = mode;
break;
}
@@ -935,24 +1087,33 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
-
- if (!acs_res->pri_channel) {
+ if (!acs_res->pri_freq) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
err = 1;
goto out;
}
+ pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
+ acs_res->pri_freq, NULL,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Could not determine primary channel number from pri_freq %u",
+ acs_res->pri_freq);
+ err = 1;
+ goto out;
+ }
- hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->channel = pri_chan->chan;
hapd->iconf->acs = 1;
- if (acs_res->sec_channel == 0)
+ if (acs_res->sec_freq == 0)
hapd->iconf->secondary_channel = 0;
- else if (acs_res->sec_channel < acs_res->pri_channel)
+ else if (acs_res->sec_freq < acs_res->pri_freq)
hapd->iconf->secondary_channel = -1;
- else if (acs_res->sec_channel > acs_res->pri_channel)
+ else if (acs_res->sec_freq > acs_res->pri_freq)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
@@ -960,32 +1121,35 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
+ hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
- if (acs_res->ch_width == 80) {
- hostapd_set_oper_centr_freq_seg0_idx(
- hapd->iconf, acs_res->vht_seg0_center_ch);
- hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
- } else if (acs_res->ch_width == 160) {
- if (acs_res->vht_seg1_center_ch == 0) {
+ if (acs_res->ch_width == 40) {
+ if (is_6ghz_freq(acs_res->pri_freq))
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
+ } else if (acs_res->ch_width == 80) {
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg0_center_ch);
+ if (acs_res->vht_seg1_center_ch == 0) {
hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_160MHZ);
+ CHANWIDTH_80MHZ);
} else {
- hostapd_set_oper_centr_freq_seg0_idx(
- hapd->iconf,
- acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80P80MHZ);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
- hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_80P80MHZ);
}
+ } else if (acs_res->ch_width == 160) {
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
@@ -1164,12 +1328,10 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
return;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
return;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
@@ -1383,15 +1545,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
#endif /* HOSTAPD */
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if ((unsigned int) chan->freq == freq)
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+ continue;
+ chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+ if (chan)
return chan;
}
diff --git a/contrib/wpa/src/ap/fils_hlp.c b/contrib/wpa/src/ap/fils_hlp.c
index 6da514a4d0fb..0310aab52ec2 100644
--- a/contrib/wpa/src/ap/fils_hlp.c
+++ b/contrib/wpa/src/ap/fils_hlp.c
@@ -158,7 +158,7 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
ssize_t res;
u8 msgtype = 0;
int rapid_commit = 0;
- struct iphdr *iph;
+ struct ip *iph;
struct udphdr *udph;
struct wpabuf *resp;
const u8 *rpos;
@@ -259,14 +259,14 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
wpabuf_put_be16(resp, ETH_P_IP);
iph = wpabuf_put(resp, sizeof(*iph));
- iph->version = 4;
- iph->ihl = sizeof(*iph) / 4;
- iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
- iph->ttl = 1;
- iph->protocol = 17; /* UDP */
- iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
- iph->daddr = dhcp->client_ip;
- iph->check = ip_checksum(iph, sizeof(*iph));
+ iph->ip_v = 4;
+ iph->ip_hl = sizeof(*iph) / 4;
+ iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ip_ttl = 1;
+ iph->ip_p = 17; /* UDP */
+ iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->ip_dst.s_addr = dhcp->client_ip;
+ iph->ip_sum = ip_checksum(iph, sizeof(*iph));
udph = wpabuf_put(resp, sizeof(*udph));
udph->uh_sport = htons(DHCP_SERVER_PORT);
udph->uh_dport = htons(DHCP_CLIENT_PORT);
@@ -479,13 +479,13 @@ static int fils_process_hlp_udp(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
+ const struct ip *iph;
const struct udphdr *udph;
u16 sport, dport, ulen;
if (len < sizeof(*iph) + sizeof(*udph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
udph = (const struct udphdr *) (iph + 1);
sport = ntohs(udph->uh_sport);
dport = ntohs(udph->uh_dport);
@@ -510,24 +510,24 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
- u16 tot_len;
+ const struct ip *iph;
+ uint16_t ip_len;
if (len < sizeof(*iph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
if (ip_checksum(iph, sizeof(*iph)) != 0) {
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
return 0;
}
- tot_len = ntohs(iph->tot_len);
- if (tot_len > len)
+ ip_len = ntohs(iph->ip_len);
+ if (ip_len > len)
return 0;
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
- iph->saddr, iph->daddr, iph->protocol);
- switch (iph->protocol) {
+ iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
+ switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
}
diff --git a/contrib/wpa/src/ap/gas_serv.c b/contrib/wpa/src/ap/gas_serv.c
index 9567e202a7f0..90f15778b5d1 100644
--- a/contrib/wpa/src/ap/gas_serv.c
+++ b/contrib/wpa/src/ap/gas_serv.c
@@ -1555,11 +1555,14 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
di->prot = prot;
di->sd_resp = buf;
di->sd_resp_pos = 0;
+ di->dpp = 1;
tx_buf = gas_build_initial_resp(
dialog_token, WLAN_STATUS_SUCCESS,
- comeback_delay, 10);
- if (tx_buf)
+ comeback_delay, 10 + 2);
+ if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, 0);
+ }
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1782,9 +1785,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
tx_buf = gas_build_comeback_resp(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id, more, 0,
- 10 + frag_len);
+ 10 + 2 + frag_len);
if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, frag_len);
wpabuf_put_buf(tx_buf, buf);
}
} else
diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c
index bf1975fbd283..913a8e29e16d 100644
--- a/contrib/wpa/src/ap/hostapd.c
+++ b/contrib/wpa/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
@@ -28,7 +29,6 @@
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
-#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
@@ -58,8 +58,10 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WEP
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+#endif /* CONFIG_WEP */
static int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
@@ -74,6 +76,8 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int ret;
for (i = 0; i < interfaces->count; i++) {
+ if (!interfaces->iface[i])
+ continue;
ret = cb(interfaces->iface[i], ctx);
if (ret)
return ret;
@@ -89,7 +93,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
return;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
}
@@ -101,7 +107,8 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
return;
if (hapd->conf->wmm_enabled < 0)
- hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
+ hapd->conf->wmm_enabled = hapd->iconf->ieee80211n |
+ hapd->iconf->ieee80211ax;
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
@@ -142,7 +149,9 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
@@ -170,7 +179,9 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j],
WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(iface->bss[j]);
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration
@@ -284,6 +295,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
const char *ifname)
{
@@ -292,26 +305,24 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
if (!ifname || !hapd->drv_priv)
return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
- 0, NULL, 0, NULL, 0)) {
+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+ 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
}
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
- NULL, i, 0, NULL,
- 0, NULL, 0)) {
+ NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
}
}
}
-#endif /* CONFIG_IEEE80211W */
}
@@ -328,11 +339,12 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
- if (ssid->wep.default_len &&
+ if (ssid->wep.default_len && ssid->wep.key[idx] &&
hostapd_drv_set_key(hapd->conf->iface,
- hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+ hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx],
- ssid->wep.len[idx])) {
+ ssid->wep.len[idx],
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
@@ -340,8 +352,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
return errors;
}
+#endif /* CONFIG_WEP */
+
-static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
@@ -363,8 +377,6 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- iapp_deinit(hapd->iapp);
- hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@@ -381,6 +393,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_DPP
hostapd_dpp_deinit(hapd);
gas_query_ap_deinit(hapd->gas);
+ hapd->gas = NULL;
#endif /* CONFIG_DPP */
authsrv_deinit(hapd);
@@ -403,6 +416,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
}
wpabuf_free(hapd->time_adv);
+ hapd->time_adv = NULL;
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
@@ -418,16 +432,23 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hapd->tmp_eap_user.identity_len);
bin_clear_free(hapd->tmp_eap_user.password,
hapd->tmp_eap_user.password_len);
+ os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
#endif /* CONFIG_SQLITE */
#ifdef CONFIG_MESH
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
+ /* handling setup failure is already done */
+ hapd->setup_complete_cb = NULL;
#endif /* CONFIG_MESH */
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
+#ifdef CONFIG_OCV
+ eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_SAE
{
struct hostapd_sae_commit_queue *q;
@@ -481,14 +502,12 @@ static void sta_track_deinit(struct hostapd_iface *iface)
}
-static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
if (iface->current_mode)
acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -529,6 +548,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
@@ -557,10 +578,13 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
- hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+ hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
- hapd->conf->ssid.wep.len[i])) {
+ hapd->conf->ssid.wep.len[i],
+ i == hapd->conf->ssid.wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
@@ -573,6 +597,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
return 0;
}
+#endif /* CONFIG_WEP */
+
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
@@ -604,11 +630,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
}
-static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_WEP
hostapd_clear_wep(hapd);
+#endif /* CONFIG_WEP */
}
@@ -1146,7 +1174,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
}
if (conf->wmm_enabled < 0)
- conf->wmm_enabled = hapd->iconf->ieee80211n;
+ conf->wmm_enabled = hapd->iconf->ieee80211n |
+ hapd->iconf->ieee80211ax;
#ifdef CONFIG_IEEE80211R_AP
if (is_zero_ether_addr(conf->r1_key_holder))
@@ -1159,13 +1188,15 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
#endif /* CONFIG_MESH */
if (flush_old_stations)
- hostapd_flush_old_stations(hapd,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_flush(hapd);
hostapd_set_privacy(hapd, 0);
- hostapd_broadcast_wep_clear(hapd);
+#ifdef CONFIG_WEP
+ if (!hostapd_drv_nl80211(hapd))
+ hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
+#endif /* CONFIG_WEP */
/*
* Fetch the SSID from the system and use it or,
@@ -1195,8 +1226,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
}
+ /*
+ * Short SSID calculation is identical to FCS and it is defined in
+ * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
+ */
+ conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
if (!hostapd_drv_none(hapd)) {
- wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+ wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
conf->iface, MAC2STR(hapd->own_addr),
wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@@ -1298,13 +1335,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
- wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
- "failed.");
- return -1;
- }
-
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
@@ -1352,6 +1382,21 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
return -1;
+ if (flush_old_stations && !conf->start_disabled &&
+ conf->broadcast_deauth) {
+ u8 addr[ETH_ALEN];
+
+ /* Should any previously associated STA not have noticed that
+ * the AP had stopped and restarted, send one more
+ * deauthentication notification now that the AP is ready to
+ * operate. */
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Deauthenticate all stations at BSS start");
+ os_memset(addr, 0xff, ETH_ALEN);
+ hostapd_drv_sta_deauth(hapd, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
return -1;
@@ -1584,6 +1629,71 @@ static int setup_interface(struct hostapd_iface *iface)
}
+static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
+{
+ int freq, i, j;
+
+ if (!iface->conf->channel)
+ return 0;
+ if (iface->conf->op_class) {
+ freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+ iface->conf->channel);
+ if (freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Could not convert op_class %u channel %u to operating frequency",
+ iface->conf->op_class, iface->conf->channel);
+ return -1;
+ }
+ iface->freq = freq;
+ return 0;
+ }
+
+ /* Old configurations using only 2.4/5/60 GHz bands may not specify the
+ * op_class parameter. Select a matching channel from the configured
+ * mode using the channel parameter for these cases.
+ */
+ for (j = 0; j < iface->num_hw_features; j++) {
+ struct hostapd_hw_modes *mode = &iface->hw_features[j];
+
+ if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ iface->conf->hw_mode != mode->mode)
+ continue;
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->chan == iface->conf->channel &&
+ !is_6ghz_freq(chan->freq)) {
+ iface->freq = chan->freq;
+ return 0;
+ }
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Could not determine operating frequency");
+ return -1;
+}
+
+
+static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface)
+{
+ int bw, seg0;
+
+ if (!is_6ghz_op_class(iface->conf->op_class))
+ return;
+
+ seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+ bw = center_idx_to_bw_6ghz(seg0);
+ /* Assign the secondary channel if absent in config for
+ * bandwidths > 20 MHz */
+ if (bw > 20 && !iface->conf->secondary_channel) {
+ if (((iface->conf->channel - 1) / 4) % 2)
+ iface->conf->secondary_channel = -1;
+ else
+ iface->conf->secondary_channel = 1;
+ }
+}
+
+
static int setup_interface2(struct hostapd_iface *iface)
{
iface->wait_channel_update = 0;
@@ -1592,7 +1702,21 @@ static int setup_interface2(struct hostapd_iface *iface)
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
- int ret = hostapd_select_hw_mode(iface);
+ int ret;
+
+ ret = configured_fixed_chan_to_freq(iface);
+ if (ret < 0)
+ goto fail;
+
+ if (iface->conf->op_class) {
+ int ch_width;
+
+ ch_width = op_class_to_ch_width(iface->conf->op_class);
+ hostapd_set_oper_chwidth(iface->conf, ch_width);
+ hostapd_set_6ghz_sec_chan(iface);
+ }
+
+ ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
@@ -1602,6 +1726,12 @@ static int setup_interface2(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
return 0;
}
+ ret = hostapd_check_edmg_capab(iface);
+ if (ret < 0)
+ goto fail;
+ ret = hostapd_check_he_6ghz_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -1694,7 +1824,7 @@ static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct sta_info *s = (struct sta_info *) *get_ctx;
@@ -1716,7 +1846,7 @@ static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
static const u8 * fst_hostapd_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct hostapd_data *hapd = ctx;
@@ -1728,7 +1858,7 @@ static const u8 * fst_hostapd_get_peer_first(void *ctx,
static const u8 * fst_hostapd_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return fst_hostapd_get_sta(get_ctx, mb_only);
}
@@ -1816,6 +1946,13 @@ static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
if (!bss->conf->owe_transition_ifname[0])
continue;
+ if (bss->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Interface %s state %s - defer beacon update",
+ bss->conf->iface,
+ hostapd_state_text(bss->iface->state));
+ continue;
+ }
res = hostapd_owe_trans_get_info(bss);
if (res == 0)
continue;
@@ -1873,12 +2010,11 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
goto fail;
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (iface->conf->channel) {
+ if (iface->freq) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
- iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
hostapd_hw_mode_txt(iface->conf->hw_mode),
@@ -1926,6 +2062,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
if (!delay_apply_cfg &&
hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
+ hapd->iconf->enable_edmg,
+ hapd->iconf->edmg_channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
@@ -2049,6 +2187,13 @@ dfs_offload:
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+#ifdef CONFIG_MESH
+ if (delay_apply_cfg && !iface->mconf) {
+ wpa_printf(MSG_ERROR, "Error while completing mesh init");
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
+
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
@@ -2189,10 +2334,12 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
{
int ret;
+ if (!iface->conf)
+ return -1;
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
- iface->bss[0]->conf->iface);
+ iface->conf->bss[0]->iface);
return -1;
}
@@ -2288,12 +2435,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
hostapd_bss_deinit(iface->bss[j]);
}
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
}
@@ -2576,6 +2721,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
+ if (!hapd_iface)
+ return -1;
+
+ if (hapd_iface->enable_iface_cb)
+ return hapd_iface->enable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
hapd_iface->conf->bss[0]->iface);
@@ -2637,6 +2788,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
if (hapd_iface == NULL)
return -1;
+ if (hapd_iface->disable_iface_cb)
+ return hapd_iface->disable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv == NULL) {
wpa_printf(MSG_INFO, "Interface %s already disabled",
hapd_iface->conf->bss[0]->iface);
@@ -3057,10 +3211,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
-
- /* IEEE 802.11F (IAPP) */
- if (hapd->conf->ieee802_11f)
- iapp_new_station(hapd->iapp, sta);
+ sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
@@ -3298,7 +3449,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
- conf->channel, conf->ieee80211n,
+ conf->channel, conf->enable_edmg,
+ conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
@@ -3436,15 +3588,23 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
}
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params)
{
- if (vht_enabled)
+ if (freq_params->he_enabled)
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
+ else
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
+
+ if (freq_params->vht_enabled)
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
else
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+ HOSTAPD_LEVEL_INFO,
+ "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+ hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
@@ -3571,3 +3731,25 @@ void hostapd_periodic_iface(struct hostapd_iface *iface)
#endif /* CONFIG_NO_RADIUS */
}
}
+
+
+#ifdef CONFIG_OCV
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->post_csa_sa_query)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
+ " did not start SA Query after CSA - disconnect",
+ MAC2STR(sta->addr));
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+}
+#endif /* CONFIG_OCV */
diff --git a/contrib/wpa/src/ap/hostapd.h b/contrib/wpa/src/ap/hostapd.h
index 518c7f10bc37..07d0aaa92100 100644
--- a/contrib/wpa/src/ap/hostapd.h
+++ b/contrib/wpa/src/ap/hostapd.h
@@ -38,6 +38,10 @@ union wps_event_data;
struct mesh_conf;
#endif /* CONFIG_MESH */
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_COOKIE_LEN 8
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
struct hostapd_iface;
struct hapd_interfaces {
@@ -72,6 +76,11 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
};
enum hostapd_chan_status {
@@ -179,13 +188,12 @@ struct hostapd_data {
u64 acct_session_id;
struct radius_das_data *radius_das;
- struct iapp_data *iapp;
-
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
+ struct eap_config *eap_cfg;
struct rsn_preauth_interface *preauth_iface;
struct os_reltime michael_mic_failure;
@@ -318,10 +326,10 @@ struct hostapd_data {
#ifdef CONFIG_SAE
/** Key used for generating SAE anti-clogging tokens */
- u8 sae_token_key[8];
- struct os_reltime last_sae_token_key_update;
- u16 sae_token_idx;
- u16 sae_pending_token_idx[256];
+ u8 comeback_key[8];
+ struct os_reltime last_comeback_key_update;
+ u16 comeback_idx;
+ u16 comeback_pending_idx[256];
int dot11RSNASAERetransPeriod; /* msec */
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
@@ -337,12 +345,17 @@ struct hostapd_data {
u8 last_gtk[WPA_GTK_MAX_LEN];
size_t last_gtk_len;
-#ifdef CONFIG_IEEE80211W
enum wpa_alg last_igtk_alg;
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
-#endif /* CONFIG_IEEE80211W */
+
+ enum wpa_alg last_bigtk_alg;
+ int last_bigtk_key_idx;
+ u8 last_bigtk[WPA_BIGTK_MAX_LEN];
+ size_t last_bigtk_len;
+
+ bool force_backlog_bytes;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -359,6 +372,8 @@ struct hostapd_data {
int dhcp_sock; /* UDP socket used with the DHCP server */
+ struct ptksa_cache *ptksa;
+
#ifdef CONFIG_DPP
int dpp_init_done;
struct dpp_authentication *dpp_auth;
@@ -380,6 +395,16 @@ struct hostapd_data {
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_presence_announcement;
+ struct dpp_bootstrap_info *dpp_chirp_bi;
+ int dpp_chirp_freq;
+ int *dpp_chirp_freqs;
+ int dpp_chirp_iter;
+ int dpp_chirp_round;
+ int dpp_chirp_scan_done;
+ int dpp_chirp_listen;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;
@@ -398,6 +423,10 @@ struct hostapd_data {
#ifdef CONFIG_SQLITE
sqlite3 *rad_attr_db;
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
};
@@ -465,9 +494,7 @@ struct hostapd_iface {
struct ap_info *ap_hash[STA_HASH_SIZE];
u64 drv_flags;
-
- /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
- unsigned int smps_modes;
+ u64 drv_flags2;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -566,6 +593,9 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+
+ int (*enable_iface_cb)(struct hostapd_iface *iface);
+ int (*disable_iface_cb)(struct hostapd_iface *iface);
};
/* hostapd.c */
@@ -594,13 +624,17 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
+void hostapd_free_hapd_data(struct hostapd_data *hapd);
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_csa_in_progress(struct hostapd_iface *iface);
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@@ -609,6 +643,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/contrib/wpa/src/ap/hs20.c b/contrib/wpa/src/ap/hs20.c
index 532580e7c66c..05e9b9d20fd7 100644
--- a/contrib/wpa/src/ap/hs20.c
+++ b/contrib/wpa/src/ap/hs20.c
@@ -80,15 +80,15 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
- if (hapd->conf->ocv)
+ if (hapd->conf->ocv &&
+ (hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
capab |= WPA_CAPABILITY_OCVC;
#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
diff --git a/contrib/wpa/src/ap/hw_features.c b/contrib/wpa/src/ap/hw_features.c
index c1f19e26b550..bb5404fa7dd4 100644
--- a/contrib/wpa/src/ap/hw_features.c
+++ b/contrib/wpa/src/ap/hw_features.c
@@ -224,16 +224,27 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
}
-#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
- int pri_chan, sec_chan;
+ int pri_freq, sec_freq;
+ struct hostapd_channel_data *p_chan, *s_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
+
+ if (!iface->current_mode)
+ return 0;
+
+ p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
- return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
- sec_chan);
+ s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+
+ return allowed_ht40_channel_pair(iface->current_mode->mode,
+ p_chan, s_chan);
}
@@ -241,9 +252,11 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
{
if (iface->conf->secondary_channel > 0) {
iface->conf->channel += 4;
+ iface->freq += 20;
iface->conf->secondary_channel = -1;
} else {
iface->conf->channel -= 4;
+ iface->freq -= 20;
iface->conf->secondary_channel = 1;
}
}
@@ -252,13 +265,23 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_chan, sec_chan;
+ unsigned int pri_freq, sec_freq;
int res;
+ struct hostapd_channel_data *pri_chan, *sec_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
+
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
+ sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
- res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
if (res == 2) {
if (iface->conf->no_pri_sec_switch) {
@@ -290,7 +313,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
int oper40;
- int res;
+ int res = 0;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
* allowed per IEEE Std 802.11-2012, 10.15.3.2 */
@@ -326,7 +349,24 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
}
}
- res = ieee80211n_allowed_ht40_channel_pair(iface);
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->secondary_channel &&
+ iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->ieee80211ax) {
+ struct he_capabilities *he_cap;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_DEBUG,
+ "HE: 40 MHz channel width is not supported in 2.4 GHz; clear secondary channel configuration");
+ iface->conf->secondary_channel = 0;
+ }
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ if (iface->conf->secondary_channel)
+ res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
@@ -352,7 +392,7 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
@@ -397,7 +437,7 @@ static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0) {
affected_start = pri_freq - 10;
affected_end = pri_freq + 30;
@@ -537,26 +577,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- switch (conf & HT_CAP_INFO_SMPS_MASK) {
- case HT_CAP_INFO_SMPS_STATIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-STATIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DYNAMIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-DYNAMIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DISABLED:
- default:
- break;
- }
-
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -663,13 +683,13 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
}
#endif /* CONFIG_IEEE80211AX */
-#endif /* CONFIG_IEEE80211N */
-
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
-#ifdef CONFIG_IEEE80211N
int ret;
+
+ if (is_6ghz_freq(iface->freq))
+ return 0;
if (!iface->conf->ieee80211n)
return 0;
@@ -698,21 +718,92 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
-#endif /* CONFIG_IEEE80211N */
return 0;
}
+int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ struct hostapd_hw_modes *mode = iface->hw_features;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 0;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+
+ if (mode->edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return 0;
+
+ wpa_printf(MSG_WARNING, "Requested EDMG configuration is not valid");
+ wpa_printf(MSG_INFO, "EDMG capab: channels 0x%x, bw_config %d",
+ mode->edmg.channels, mode->edmg.bw_config);
+ wpa_printf(MSG_INFO,
+ "Requested EDMG configuration: channels 0x%x, bw_config %d",
+ edmg.channels, edmg.bw_config);
+ return -1;
+}
+
+
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211AX
+ struct he_capabilities *he_cap;
+ u16 hw;
+
+ if (!iface->current_mode || !is_6ghz_freq(iface->freq))
+ return 0;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ hw = he_cap->he_6ghz_capa;
+ if (iface->conf->he_6ghz_max_mpdu >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max MPDU length");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_max_ampdu_len_exp >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max AMPDU Length Exponent");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_rx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Rx Antenna Pattern");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_tx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Tx Antenna Pattern");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211AX */
+ return 0;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
- int channel, int primary)
+ int frequency, int primary)
{
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
+ iface->hw_features, iface->num_hw_features);
if (!chan)
return 0;
@@ -721,8 +812,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
return 1;
wpa_printf(MSG_INFO,
- "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
- channel, primary ? "primary" : "secondary",
+ "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ frequency, primary ? "primary" : "secondary",
chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -730,37 +821,123 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
}
-static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
{
- int secondary_chan;
+ int i, contiguous = 0;
+ int num_of_enabled = 0;
+ int max_contiguous = 0;
+ struct ieee80211_edmg_config edmg;
struct hostapd_channel_data *pri_chan;
- pri_chan = hw_get_channel_chan(iface->current_mode,
- iface->conf->channel, NULL);
- if (!pri_chan)
+ if (!iface->conf->enable_edmg)
+ return 1;
+
+ if (!iface->current_mode)
return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ pri_chan->chan,
+ &edmg);
+ if (!(edmg.channels & BIT(pri_chan->chan - 1)))
+ return 0;
+
+ /* 60 GHz channels 1..6 */
+ for (i = 0; i < 6; i++) {
+ int freq = 56160 + 2160 * (i + 1);
- if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+ if (edmg.channels & BIT(i)) {
+ contiguous++;
+ num_of_enabled++;
+ } else {
+ contiguous = 0;
+ continue;
+ }
+
+ /* P802.11ay defines that the total number of subfields
+ * set to one does not exceed 4.
+ */
+ if (num_of_enabled > 4)
+ return 0;
+
+ if (!hostapd_is_usable_chan(iface, freq, 1))
+ return 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Check if the EDMG configuration is valid under the limitations
+ * of P802.11ay.
+ */
+ /* check bw_config against contiguous EDMG channels */
+ switch (edmg.bw_config) {
+ case EDMG_BW_CONFIG_4:
+ if (!max_contiguous)
+ return 0;
+ break;
+ case EDMG_BW_CONFIG_5:
+ if (max_contiguous < 2)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+{
+ int secondary_freq;
+ struct hostapd_channel_data *pri_chan;
+
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR, "Primary frequency not present");
+ return 0;
+ }
+ if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
+ wpa_printf(MSG_ERROR, "Primary frequency not allowed");
+ return 0;
+ }
+ if (!hostapd_is_usable_edmg(iface))
return 0;
if (!iface->conf->secondary_channel)
return 1;
+ if (hostapd_is_usable_chan(iface, iface->freq +
+ iface->conf->secondary_channel * 20, 0)) {
+ if (iface->conf->secondary_channel == 1 &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
+ return 1;
+ if (iface->conf->secondary_channel == -1 &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))
+ return 1;
+ }
if (!iface->conf->ht40_plus_minus_allowed)
- return hostapd_is_usable_chan(
- iface, iface->conf->channel +
- iface->conf->secondary_channel * 4, 0);
+ return 0;
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
- secondary_chan = iface->conf->channel + 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ secondary_freq = iface->freq + 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
- secondary_chan = iface->conf->channel - 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ secondary_freq = iface->freq - 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
@@ -770,10 +947,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
}
+static void hostapd_determine_mode(struct hostapd_iface *iface)
+{
+ int i;
+ enum hostapd_hw_mode target_mode;
+
+ if (iface->current_mode ||
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
+ return;
+
+ if (iface->freq < 4000)
+ target_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (iface->freq > 50000)
+ target_mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ target_mode = HOSTAPD_MODE_IEEE80211A;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ struct hostapd_hw_modes *mode;
+
+ mode = &iface->hw_features[i];
+ if (mode->mode == target_mode) {
+ iface->current_mode = mode;
+ iface->conf->hw_mode = mode->mode;
+ break;
+ }
+ }
+
+ if (!iface->current_mode)
+ wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+}
+
+
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
- if (iface->conf->channel) {
+ if (iface->freq) {
+ hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@@ -807,9 +1017,9 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) not found from the "
- "channel list of current mode (%d) %s",
+ "Configured channel (%d) or frequency (%d) (secondary_channel=%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
+ iface->freq, iface->conf->secondary_channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -829,9 +1039,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
case HOSTAPD_CHAN_VALID:
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
- hostapd_hw_get_freq(iface->bss[0],
- iface->conf->channel),
- iface->conf->channel);
+ iface->freq, iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@@ -889,16 +1097,28 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
+ int chan;
+
if (mode->mode == iface->conf->hw_mode) {
+ if (iface->freq > 0 &&
+ !hw_mode_get_channel(mode, iface->freq, &chan))
+ continue;
+
iface->current_mode = mode;
break;
}
}
if (iface->current_mode == NULL) {
- if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
- !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
- {
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
+ wpa_printf(MSG_DEBUG,
+ "Using offloaded hw_mode=any ACS");
+ } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "Using internal ACS for hw_mode=any");
+ } else {
wpa_printf(MSG_ERROR,
"Hardware does not support configured mode");
hostapd_logger(iface->bss[0], NULL,
@@ -952,7 +1172,9 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
struct hostapd_hw_modes *mode;
if (hapd->iface->current_mode) {
- channel = hw_get_chan(hapd->iface->current_mode, freq);
+ channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
@@ -963,9 +1185,28 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
- channel = hw_get_chan(mode, freq);
+ channel = hw_get_chan(mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
return 0;
}
+
+
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ if (iface->current_mode)
+ return mode != iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211B)
+ return 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
+ return 1;
+ }
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/hw_features.h b/contrib/wpa/src/ap/hw_features.h
index ca7f22ba205b..ad0ddf7ff386 100644
--- a/contrib/wpa/src/ap/hw_features.h
+++ b/contrib/wpa/src/ap/hw_features.h
@@ -21,9 +21,13 @@ const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_check_edmg_capab(struct hostapd_iface *iface);
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -48,7 +52,7 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
static inline const char * hostapd_hw_mode_txt(int mode)
{
- return NULL;
+ return "UNKNOWN";
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@@ -61,6 +65,11 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
+static inline int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
@@ -71,6 +80,17 @@ static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
{
}
+static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ return 0;
+}
+
+static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/contrib/wpa/src/ap/ieee802_11.c b/contrib/wpa/src/ap/ieee802_11.c
index c85a28db44b7..22cce961063e 100644
--- a/contrib/wpa/src/ap/ieee802_11.c
+++ b/contrib/wpa/src/ap/ieee802_11.c
@@ -24,6 +24,8 @@
#include "common/dpp.h"
#include "common/ocv.h"
#include "common/wpa_common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -64,6 +66,23 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_PASN
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status);
+#ifdef CONFIG_FILS
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_PASN */
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue);
@@ -88,6 +107,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -98,6 +118,12 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -124,6 +150,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (h2e_required && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -132,6 +163,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -141,6 +173,12 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -170,14 +208,41 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (h2e_required) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
+ return eid;
+
+ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
+}
+
+
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
- int privacy;
+ int privacy = 0;
int dfs;
int i;
@@ -193,12 +258,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
hapd->iconf->preamble == SHORT_PREAMBLE)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+#ifdef CONFIG_WEP
privacy = hapd->conf->ssid.wep.keys_set;
if (hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len))
privacy = 1;
+#endif /* CONFIG_WEP */
if (hapd->conf->wpa)
privacy = 1;
@@ -238,6 +305,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
@@ -294,9 +362,10 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *dst, const u8 *bssid,
u16 auth_alg, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len, const char *dbg)
@@ -329,7 +398,38 @@ static int send_auth_reply(struct hostapd_data *hapd,
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len, dbg);
- if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_confirm_immediate == 2 &&
+ auth_alg == WLAN_AUTH_SAE) {
+ if (auth_transaction == 1 && sta &&
+ (resp == WLAN_STATUS_SUCCESS ||
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ resp == WLAN_STATUS_SAE_PK)) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = buf;
+ sta->sae_postponed_commit_len = rlen;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+ if (hostapd_drv_send_mlme(hapd,
+ sta->sae_postponed_commit,
+ sta->sae_postponed_commit_len,
+ 0, NULL, 0, 0) < 0)
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = NULL;
+ sta->sae_postponed_commit_len = 0;
+ }
+ }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
else
reply_res = WLAN_STATUS_SUCCESS;
@@ -349,7 +449,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
struct sta_info *sta;
int reply_res;
- reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
auth_transaction, status, ies, ies_len,
"auth-ft-finish");
@@ -387,16 +487,17 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
}
-static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update)
+static const char * sae_get_password(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const char *rx_id,
+ struct sae_password_entry **pw_entry,
+ struct sae_pt **s_pt,
+ const struct sae_pk **s_pk)
{
- struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
- const char *rx_id = NULL;
-
- if (sta->sae->tmp)
- rx_id = sta->sae->tmp->pw_id;
+ struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -408,18 +509,70 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
os_strcmp(rx_id, pw->identifier) != 0)
continue;
password = pw->password;
+ pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
break;
}
- if (!password)
- password = hapd->conf->ssid.wpa_passphrase;
if (!password) {
+ password = hapd->conf->ssid.wpa_passphrase;
+ pt = hapd->conf->ssid.pt;
+ }
+
+ if (pw_entry)
+ *pw_entry = pw;
+ if (s_pt)
+ *s_pt = pt;
+ if (s_pk)
+ *s_pk = pk;
+
+ return password;
+}
+
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta, int update,
+ int status_code)
+{
+ struct wpabuf *buf;
+ const char *password = NULL;
+ struct sae_password_entry *pw;
+ const char *rx_id = NULL;
+ int use_pt = 0;
+ struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
+
+ if (sta->sae->tmp) {
+ rx_id = sta->sae->tmp->pw_id;
+ use_pt = sta->sae->h2e;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
+ os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (rx_id && hapd->conf->sae_pwe != 3)
+ use_pt = 1;
+ else if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
+ use_pt = 1;
+
+ password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
+ if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
- if (update &&
+ if (update && use_pt &&
+ sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+ NULL, pk) < 0)
+ return NULL;
+
+ if (update && !use_pt &&
sae_prepare_commit(hapd->own_addr, sta->addr,
- (u8 *) password, os_strlen(password), rx_id,
+ (u8 *) password, os_strlen(password),
sta->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
@@ -436,10 +589,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
(rx_id ? 3 + os_strlen(rx_id) : 0));
- if (buf == NULL)
- return NULL;
- sae_write_commit(sta->sae, buf, sta->sae->tmp ?
- sta->sae->tmp->anti_clogging_token : NULL, rx_id);
+ if (buf &&
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL,
+ rx_id) < 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
return buf;
}
@@ -454,7 +610,17 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
if (buf == NULL)
return NULL;
- sae_write_confirm(sta->sae, buf);
+#ifdef CONFIG_SAE_PK
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sta->sae->tmp)
+ sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
+
+ if (sae_write_confirm(sta->sae, buf) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
return buf;
}
@@ -462,19 +628,36 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update)
+ const u8 *bssid, int update, int status_code)
{
struct wpabuf *data;
int reply_res;
+ u16 status;
- data = auth_build_sae_commit(hapd, sta, update);
+ data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
- WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ if (sta->sae->tmp && sta->sae->pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (sta->sae->tmp && sta->sae->h2e)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->sae_commit_status >= 0 &&
+ hapd->conf->sae_commit_status != status) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Override SAE commit status code %u --> %d",
+ status, hapd->conf->sae_commit_status);
+ status = hapd->conf->sae_commit_status;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1,
+ status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
@@ -494,7 +677,8 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
@@ -503,49 +687,62 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
return reply_res;
}
+#endif /* CONFIG_SAE */
-static int use_sae_anti_clogging(struct hostapd_data *hapd)
+
+#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
+
+static int use_anti_clogging(struct hostapd_data *hapd)
{
struct sta_info *sta;
unsigned int open = 0;
- if (hapd->conf->sae_anti_clogging_threshold == 0)
+ if (hapd->conf->anti_clogging_threshold == 0)
return 1;
for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!sta->sae)
- continue;
- if (sta->sae->state != SAE_COMMITTED &&
- sta->sae->state != SAE_CONFIRMED)
- continue;
- open++;
- if (open >= hapd->conf->sae_anti_clogging_threshold)
+#ifdef CONFIG_SAE
+ if (sta->sae &&
+ (sta->sae->state == SAE_COMMITTED ||
+ sta->sae->state == SAE_CONFIRMED))
+ open++;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_PASN
+ if (sta->pasn && sta->pasn->ecdh)
+ open++;
+#endif /* CONFIG_PASN */
+ if (open >= hapd->conf->anti_clogging_threshold)
return 1;
}
+#ifdef CONFIG_SAE
/* In addition to already existing open SAE sessions, check whether
* there are enough pending commit messages in the processing queue to
* potentially result in too many open sessions. */
if (open + dl_list_len(&hapd->sae_commit_queue) >=
- hapd->conf->sae_anti_clogging_threshold)
+ hapd->conf->anti_clogging_threshold)
return 1;
+#endif /* CONFIG_SAE */
return 0;
}
-static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr,
+ u8 *idx)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, hash);
- return hash[0];
+ if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key),
+ addr, ETH_ALEN, hash) < 0)
+ return -1;
+ *idx = hash[0];
+ return 0;
}
-static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
- const u8 *token, size_t token_len)
+static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *token, size_t token_len)
{
u8 mac[SHA256_MAC_LEN];
const u8 *addrs[2];
@@ -553,12 +750,13 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
u16 token_idx;
u8 idx;
- if (token_len != SHA256_MAC_LEN)
+ if (token_len != SHA256_MAC_LEN ||
+ comeback_token_hash(hapd, addr, &idx) < 0)
return -1;
- idx = sae_token_hash(hapd, addr);
- token_idx = hapd->sae_pending_token_idx[idx];
+ token_idx = hapd->comeback_pending_idx[idx];
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
- wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+ wpa_printf(MSG_DEBUG,
+ "Comeback: Invalid anti-clogging token from "
MACSTR " - token_idx 0x%04x, expected 0x%04x",
MAC2STR(addr), WPA_GET_BE16(token), token_idx);
return -1;
@@ -568,19 +766,19 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
len[0] = ETH_ALEN;
addrs[1] = token;
len[1] = 2;
- if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
2, addrs, len, mac) < 0 ||
os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
return -1;
- hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
+ hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */
return 0;
}
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
- int group, const u8 *addr)
+ int group, const u8 *addr, int h2e)
{
struct wpabuf *buf;
u8 *token;
@@ -592,32 +790,44 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
u16 token_idx;
os_get_reltime(&now);
- if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
- os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
- hapd->sae_token_idx == 0xffff) {
- if (random_get_bytes(hapd->sae_token_key,
- sizeof(hapd->sae_token_key)) < 0)
+ if (!os_reltime_initialized(&hapd->last_comeback_key_update) ||
+ os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) ||
+ hapd->comeback_idx == 0xffff) {
+ if (random_get_bytes(hapd->comeback_key,
+ sizeof(hapd->comeback_key)) < 0)
return NULL;
- wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
- hapd->sae_token_key, sizeof(hapd->sae_token_key));
- hapd->last_sae_token_key_update = now;
- hapd->sae_token_idx = 0;
- os_memset(hapd->sae_pending_token_idx, 0,
- sizeof(hapd->sae_pending_token_idx));
+ wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
+ hapd->comeback_key, sizeof(hapd->comeback_key));
+ hapd->last_comeback_key_update = now;
+ hapd->comeback_idx = 0;
+ os_memset(hapd->comeback_pending_idx, 0,
+ sizeof(hapd->comeback_pending_idx));
}
- buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+ buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+ if (group)
+ wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+
+ if (h2e) {
+ /* Encapsulate Anti-clogging Token field in a container IE */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ }
- p_idx = sae_token_hash(hapd, addr);
- token_idx = hapd->sae_pending_token_idx[p_idx];
+ if (comeback_token_hash(hapd, addr, &p_idx) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ token_idx = hapd->comeback_pending_idx[p_idx];
if (!token_idx) {
- hapd->sae_token_idx++;
- token_idx = hapd->sae_token_idx;
- hapd->sae_pending_token_idx[p_idx] = token_idx;
+ hapd->comeback_idx++;
+ token_idx = hapd->comeback_idx;
+ hapd->comeback_pending_idx[p_idx] = token_idx;
}
WPA_PUT_BE16(idx, token_idx);
token = wpabuf_put(buf, SHA256_MAC_LEN);
@@ -625,7 +835,7 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
len[0] = ETH_ALEN;
addrs[1] = idx;
len[1] = sizeof(idx);
- if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
2, addrs, len, token) < 0) {
wpabuf_free(buf);
return NULL;
@@ -635,6 +845,10 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
return buf;
}
+#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
+
+
+#ifdef CONFIG_SAE
static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
{
@@ -663,7 +877,7 @@ 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);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -754,6 +968,9 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
mlme_authenticate_indication(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+ crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
+ sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
+ sta->sae->peer_commit_scalar = NULL;
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmkid);
sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
@@ -761,8 +978,8 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction, int allow_reuse,
- int *sta_removed)
+ const u8 *bssid, u16 auth_transaction, u16 status_code,
+ int allow_reuse, int *sta_removed)
{
int ret;
@@ -777,8 +994,16 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
+ if (sta->sae->tmp) {
+ sta->sae->h2e =
+ (status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
+ sta->sae->pk =
+ status_code == WLAN_STATUS_SAE_PK;
+ }
ret = auth_sae_send_commit(hapd, sta, bssid,
- !allow_reuse);
+ !allow_reuse, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -787,14 +1012,17 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
- * In mesh case, both Commit and Confirm can be sent
- * immediately. In infrastructure BSS, only a single
- * Authentication frame (Commit) is expected from the AP
- * here and the second one (Confirm) will be sent once
- * the STA has sent its second Authentication frame
- * (Confirm).
+ * In mesh case, both Commit and Confirm are sent
+ * immediately. In infrastructure BSS, by default, only
+ * a single Authentication frame (Commit) is expected
+ * from the AP here and the second one (Confirm) will
+ * be sent once the STA has sent its second
+ * Authentication frame (Confirm). This behavior can be
+ * overridden with explicit configuration so that the
+ * infrastructure BSS case sends both frames together.
*/
- if (hapd->conf->mesh & MESH_ENABLED) {
+ if ((hapd->conf->mesh & MESH_ENABLED) ||
+ hapd->conf->sae_confirm_immediate) {
/*
* Send both Commit and Confirm immediately
* based on SAE finite state machine
@@ -845,7 +1073,8 @@ 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, 0);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+ status_code);
if (ret)
return ret;
@@ -868,7 +1097,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
* additional events.
*/
return sae_sm_step(hapd, sta, bssid, auth_transaction,
- 0, sta_removed);
+ WLAN_STATUS_SUCCESS, 0, sta_removed);
}
break;
case SAE_CONFIRMED:
@@ -878,7 +1107,8 @@ 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, 1,
+ status_code);
if (ret)
return ret;
@@ -906,7 +1136,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -976,6 +1207,85 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
}
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+ int sae_pwe = hapd->conf->sae_pwe;
+ int id_in_use;
+ bool sae_pk = false;
+
+ id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+ if (id_in_use == 2 && sae_pwe != 3)
+ sae_pwe = 1;
+ else if (id_in_use == 1 && sae_pwe == 0)
+ sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+ if (sae_pwe == 0 && sae_pk)
+ sae_pwe = 2;
+#endif /* CONFIG_SAE_PK */
+
+ return ((sae_pwe == 0 || sae_pwe == 3) &&
+ status_code == WLAN_STATUS_SUCCESS) ||
+ (sae_pwe == 1 &&
+ (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
+ (sae_pwe == 2 &&
+ (status_code == WLAN_STATUS_SUCCESS ||
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+ struct sae_data *sae)
+{
+ const struct wpabuf *groups;
+ size_t i, count;
+ const u8 *pos;
+
+ if (!sae->tmp)
+ return 0;
+ groups = sae->tmp->peer_rejected_groups;
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sae_is_group_enabled(hapd, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -986,6 +1296,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
int default_groups[] = { 19, 0 };
const u8 *pos, *end;
int sta_removed = 0;
+ bool success_status;
if (!groups)
groups = default_groups;
@@ -995,7 +1306,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ resp = status_code;
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
goto remove_sta;
@@ -1003,7 +1315,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_commit_override && auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
wpabuf_len(hapd->conf->sae_commit_override),
@@ -1013,9 +1325,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_TESTING_OPTIONS */
if (!sta->sae) {
if (auth_transaction != 1 ||
- status_code != WLAN_STATUS_SUCCESS) {
- resp = -1;
- goto remove_sta;
+ !sae_status_success(hapd, status_code)) {
+ wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
+ status_code);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
}
sta->sae = os_zalloc(sizeof(*sta->sae));
if (!sta->sae) {
@@ -1080,7 +1394,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+ status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1103,7 +1418,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
goto remove_sta;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (!sae_status_success(hapd, status_code))
goto remove_sta;
if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1136,7 +1451,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, groups);
+ &token_len, groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1154,7 +1471,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
goto remove_sta;
}
- if (token && check_sae_token(hapd, sta->addr, token, token_len)
+ if (token &&
+ check_comeback_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
"incorrect token from " MACSTR,
@@ -1166,12 +1484,24 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+ if (check_sae_rejected_groups(hapd, sta->sae)) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+
+ if (!token && use_anti_clogging(hapd) && !allow_reuse) {
+ int h2e = 0;
+
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
+ if (sta->sae->tmp)
+ h2e = sta->sae->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
+ h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
- sta->addr);
+ sta->addr, h2e);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
sae_set_state(sta, SAE_NOTHING,
@@ -1180,7 +1510,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
- allow_reuse, &sta_removed);
+ status_code, allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1221,8 +1551,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
- &sta_removed);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ status_code, 0, &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1246,16 +1576,19 @@ reply:
data = wpabuf_alloc_copy(pos, 2);
sae_sme_send_external_auth_status(hapd, sta, resp);
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
}
remove_sta:
+ if (auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+ else
+ success_status = status_code == WLAN_STATUS_SUCCESS;
if (!sta_removed && sta->added_unassoc &&
- (resp != WLAN_STATUS_SUCCESS ||
- status_code != WLAN_STATUS_SUCCESS)) {
+ (resp != WLAN_STATUS_SUCCESS || !success_status)) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -1283,7 +1616,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
if (ret)
return -1;
@@ -1396,29 +1729,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
#endif /* CONFIG_SAE */
-static u16 wpa_res_to_status_code(int res)
+static u16 wpa_res_to_status_code(enum wpa_validate_result res)
{
- if (res == WPA_INVALID_GROUP)
+ switch (res) {
+ case WPA_IE_OK:
+ return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_IE:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_INVALID_GROUP:
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_PAIRWISE)
+ case WPA_INVALID_PAIRWISE:
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_AKMP)
+ case WPA_INVALID_AKMP:
return WLAN_STATUS_AKMP_NOT_VALID;
- if (res == WPA_ALLOC_FAIL)
+ case WPA_NOT_ENABLED:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_ALLOC_FAIL:
return WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
- if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
- if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-#endif /* CONFIG_IEEE80211W */
- if (res == WPA_INVALID_MDIE)
+ case WPA_INVALID_MDIE:
return WLAN_STATUS_INVALID_MDIE;
- if (res == WPA_INVALID_PMKID)
- return WLAN_STATUS_INVALID_PMKID;
- if (res != WPA_IE_OK)
+ case WPA_INVALID_PROTO:
return WLAN_STATUS_INVALID_IE;
- return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_PMKID:
+ return WLAN_STATUS_INVALID_PMKID;
+ case WPA_DENIED_OTHER_REASON:
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+ return WLAN_STATUS_INVALID_IE;
}
@@ -1438,7 +1779,7 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *end;
struct ieee802_11_elems elems;
- int res;
+ enum wpa_validate_result res;
struct wpa_ie_data rsn;
struct rsn_pmksa_cache_entry *pmksa = NULL;
@@ -1554,6 +1895,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len, NULL, 0);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
@@ -1612,11 +1955,11 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
FILS_SESSION_LEN);
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
- if (elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (elems.wrapped_data) {
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
if (!pmksa) {
#ifndef CONFIG_NO_RADIUS
if (!sta->eapol_sm) {
@@ -1626,8 +1969,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG,
"FILS: Forward EAP-Initiate/Re-auth to authentication server");
ieee802_1x_encapsulate_radius(
- hapd, sta, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ hapd, sta, elems.wrapped_data,
+ elems.wrapped_data_len);
sta->fils_pending_cb = cb;
wpa_printf(MSG_DEBUG,
"FILS: Will send Authentication frame once the response from authentication server is available");
@@ -1636,8 +1979,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
* to maintain a copy of the EAP-Initiate/Reauth
* message. */
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len,
+ elems.wrapped_data,
+ elems.wrapped_data_len,
sta->fils_erp_pmkid) == 0)
sta->fils_erp_pmkid_set = 1;
return;
@@ -1780,12 +2123,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
if (!pmksa && erp_resp) {
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(data, erp_resp);
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
@@ -1887,7 +2230,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
auth_alg = (pub ||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
- send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
@@ -1909,50 +2252,52 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len)
{
- struct wpabuf *data;
- int pub = 0;
u16 resp;
+ u32 flags = sta->flags;
- sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
+ WLAN_STA_PENDING_PASN_FILS_ERP);
- if (!sta->fils_pending_cb)
- return;
resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
- data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
- msk, msk_len, &pub);
- if (!data) {
- wpa_printf(MSG_DEBUG,
- "%s: prepare_auth_resp_fils() returned failure",
- __func__);
+
+ if (flags & WLAN_STA_PENDING_FILS_ERP) {
+ struct wpabuf *data;
+ int pub = 0;
+
+ if (!sta->fils_pending_cb)
+ return;
+
+ data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+ msk, msk_len, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() failure",
+ __func__);
+ }
+ sta->fils_pending_cb(hapd, sta, resp, data, pub);
+#ifdef CONFIG_PASN
+ } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
+ pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
+ msk, msk_len);
+#endif /* CONFIG_PASN */
}
- sta->fils_pending_cb(hapd, sta, resp, data, pub);
}
#endif /* CONFIG_FILS */
-int
-ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui, int is_probe_req)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len,
+ struct radius_sta *info)
{
int res;
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- res = hostapd_allowed_address(hapd, addr, msg, len,
- session_timeout, acct_interim_interval,
- vlan_id, psk, identity, radius_cui,
- is_probe_req);
+ res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
if (res == HOSTAPD_ACL_REJECT) {
- if (!is_probe_req)
- wpa_printf(MSG_DEBUG,
- "Station " MACSTR
- " not allowed to authenticate",
- MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
return HOSTAPD_ACL_REJECT;
}
@@ -1972,12 +2317,15 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
static int
ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, u32 session_timeout,
- u32 acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ int res, struct radius_sta *info)
{
+ u32 session_timeout = info->session_timeout;
+ u32 acct_interim_interval = info->acct_interim_interval;
+ struct vlan_description *vlan_id = &info->vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = info->psk;
+ char *identity = info->identity;
+ char *radius_cui = info->radius_cui;
+
if (vlan_id->notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -1994,20 +2342,22 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = *psk;
- *psk = NULL;
- } else {
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+ hostapd_copy_psk_list(&sta->psk, psk);
+ else
sta->psk = NULL;
- }
os_free(sta->identity);
- sta->identity = *identity;
- *identity = NULL;
+ if (identity)
+ sta->identity = os_strdup(identity);
+ else
+ sta->identity = NULL;
os_free(sta->radius_cui);
- sta->radius_cui = *radius_cui;
- *radius_cui = NULL;
+ if (radius_cui)
+ sta->radius_cui = os_strdup(radius_cui);
+ else
+ sta->radius_cui = NULL;
if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
sta->acct_interim_interval = acct_interim_interval;
@@ -2025,6 +2375,1177 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifdef CONFIG_PASN
+#ifdef CONFIG_SAE
+
+static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const char *password;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+ int groups[] = { pasn->group, 0 };
+ struct sae_pt *pt = NULL;
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 1 ||
+ status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
+ return -1;
+ }
+
+ sae_clear_data(&pasn->sae);
+ pasn->sae.state = SAE_NOTHING;
+
+ ret = sae_set_group(&pasn->sae, pasn->group);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+ return -1;
+ }
+
+ password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL);
+ if (!password || !pt) {
+ wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
+ return -1;
+ }
+
+ ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+ return -1;
+ }
+
+ res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
+ groups, 0);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
+ return -1;
+ }
+
+ /* Process the commit message and derive the PMK */
+ ret = sae_process_commit(&pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_COMMITTED;
+
+ return 0;
+}
+
+
+static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+ return -1;
+ }
+
+ res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_ACCEPTED;
+
+ /*
+ * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
+ * PASN/SAE should only be allowed with future PASN only. For now do not
+ * restrict this only for PASN.
+ */
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ pasn->sae.pmk, pasn->sae.pmkid);
+ return 0;
+}
+
+
+static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct wpabuf *buf = NULL;
+ u8 *len_ptr;
+ size_t len;
+
+ /* Need to add the entire Authentication frame body */
+ buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ /* Need to add the entire authentication frame body for the commit */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+
+ /* Write the actual commit and update the length accordingly */
+ sae_write_commit(&pasn->sae, buf, NULL, 0);
+ len = wpabuf_len(buf);
+ WPA_PUT_LE16(len_ptr, len - 2);
+
+ /* Need to add the entire Authentication frame body for the confirm */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 2);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_confirm(&pasn->sae, buf);
+ WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
+
+ pasn->sae.state = SAE_CONFIRMED;
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct wpabuf *buf = NULL;
+
+ if (!fils->erp_resp) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ return NULL;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 2);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
+
+ /* Wrapped Data */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, fils->erp_resp);
+
+ return buf;
+}
+
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
+ status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (!pasn->secret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
+ goto fail;
+ }
+
+ if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
+ fils->anonce, FILS_NONCE_LEN);
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+ fils->anonce, NULL, 0, pmk, &pmk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(pasn->secret),
+ wpabuf_len(pasn->secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, sta->pasn->kdk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+
+ wpabuf_free(pasn->secret);
+ pasn->secret = NULL;
+
+ fils->erp_resp = erp_resp;
+ ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
+ fils->erp_resp = NULL;
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
+ goto fail;
+ }
+
+ fils->state = PASN_FILS_STATE_COMPLETE;
+ return;
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ struct wpabuf *wd)
+{
+#ifdef CONFIG_NO_RADIUS
+ wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
+ return -1;
+#else /* CONFIG_NO_RADIUS */
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ struct wpabuf *fils_wd;
+ const u8 *data;
+ size_t buf_len;
+ u16 alg, seq, status;
+ int ret;
+
+ if (fils->state != PASN_FILS_STATE_NONE) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
+ return -1;
+ }
+
+ if (!wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
+ return -1;
+ }
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
+ return -1;
+ }
+
+ if (!sta->eapol_sm)
+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
+
+ ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
+
+ fils->state = PASN_FILS_STATE_PENDING_AS;
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reautt message.
+ */
+ fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+ fils->erp_pmkid);
+
+ wpabuf_free(fils_wd);
+ return 0;
+#endif /* CONFIG_NO_RADIUS */
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ switch (sta->pasn->akmp) {
+ case WPA_KEY_MGMT_PASN:
+ /* no wrapped data */
+ return NULL;
+ case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+ return pasn_get_sae_wd(hapd, sta);
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
+#endif /* CONFIG_SAE */
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return pasn_get_fils_wd(hapd, sta);
+#endif /* CONFIG_FILS */
+ /* fall through */
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ default:
+ wpa_printf(MSG_ERROR,
+ "PASN: TODO: Wrapped data for akmp=0x%x",
+ sta->pasn->akmp);
+ return NULL;
+ }
+}
+
+
+static int
+pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *cached_pmk, size_t cached_pmk_len,
+ struct wpa_pasn_params_data *pasn_data,
+ struct wpabuf *wrapped_data,
+ struct wpabuf *secret)
+{
+ static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+ u8 pmk[PMK_LEN_MAX];
+ u8 pmk_len;
+ int ret;
+
+ os_memset(pmk, 0, sizeof(pmk));
+ pmk_len = 0;
+
+ if (!cached_pmk || !cached_pmk_len)
+ wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
+
+ if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
+ wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+ pmk_len = WPA_PASN_PMK_LEN;
+ os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
+ } else if (cached_pmk && cached_pmk_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
+
+ pmk_len = cached_pmk_len;
+ os_memcpy(pmk, cached_pmk, cached_pmk_len);
+ } else {
+ switch (sta->pasn->akmp) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ if (sta->pasn->sae.state == SAE_COMMITTED) {
+ pmk_len = PMK_LEN;
+ os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
+ break;
+ }
+#endif /* CONFIG_SAE */
+ /* fall through */
+ default:
+ /* TODO: Derive PMK based on wrapped data */
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing PMK derivation");
+ return -1;
+ }
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(secret), wpabuf_len(secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, sta->pasn->kdk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+ return 0;
+}
+
+
+static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 group)
+{
+ struct wpabuf *buf, *comeback;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: Building comeback frame 2. Comeback after=%u",
+ hapd->conf->pasn_comeback_after);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ return;
+
+ wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+ sta->addr, 2,
+ WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
+
+ /*
+ * Do not include the group as a part of the token since it is not going
+ * to be used.
+ */
+ comeback = auth_build_token_req(hapd, 0, sta->addr, 0);
+ if (!comeback) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed sending auth with comeback");
+ wpabuf_free(buf);
+ return;
+ }
+
+ wpa_pasn_add_parameter_ie(buf, group,
+ WPA_PASN_WRAPPED_DATA_NO,
+ NULL, 0, comeback,
+ hapd->conf->pasn_comeback_after);
+ wpabuf_free(comeback);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
+
+ ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+ NULL, 0, 0);
+ if (ret)
+ wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
+
+ wpabuf_free(buf);
+}
+
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status)
+{
+ struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ u8 *ptr;
+ const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
+ u8 *data_buf = NULL;
+ size_t rsn_ie_len, frame_len, data_len;
+ int ret;
+ const u8 *pmkid = NULL;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+ sta->addr, 2, status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (pmksa) {
+ pmkid = pmksa->pmkid;
+#ifdef CONFIG_SAE
+ } else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
+ pmkid = sta->pasn->sae.pmkid;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ } else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
+ pmkid = sta->pasn->fils.erp_pmkid;
+#endif /* CONFIG_FILS */
+ }
+
+ if (wpa_pasn_add_rsne(buf, pmkid,
+ sta->pasn->akmp, sta->pasn->cipher) < 0)
+ goto fail;
+
+ /* No need to derive PMK if PMKSA is given */
+ if (!pmksa)
+ wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
+ else
+ sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
+
+ /* Get public key */
+ pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
+ pubkey = wpabuf_zeropad(pubkey,
+ crypto_ecdh_prime_len(sta->pasn->ecdh));
+ if (!pubkey) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+ goto fail;
+ }
+
+ wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+ sta->pasn->wrapped_data_format,
+ pubkey, true, NULL, 0);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+
+ wpabuf_free(wrapped_data_buf);
+ wrapped_data_buf = NULL;
+ wpabuf_free(pubkey);
+ pubkey = NULL;
+
+ /* Add RSNXE if needed */
+ rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (rsnxe_ie)
+ wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+
+ /* Add the mic */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, mic_len);
+ ptr = wpabuf_put(buf, mic_len);
+
+ os_memset(ptr, 0, mic_len);
+
+ frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+ frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+ rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
+ if (!rsn_ie || !rsn_ie_len)
+ goto fail;
+
+ /*
+ * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
+ * MDE, etc. Thus, do not use the returned length but instead use the
+ * length specified in the IE header.
+ */
+ data_len = rsn_ie[1] + 2;
+ if (rsnxe_ie) {
+ data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
+ if (!data_buf)
+ goto fail;
+
+ os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
+ os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
+ data_len += rsnxe_ie[1] + 2;
+ data = data_buf;
+ } else {
+ data = rsn_ie;
+ }
+
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ hapd->own_addr, sta->addr, data, data_len,
+ frame, frame_len, mic);
+ os_free(data_buf);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
+ goto fail;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->pasn_corrupt_mic) {
+ wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
+ mic[0] = ~mic[0];
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_memcpy(ptr, mic, mic_len);
+
+done:
+ wpa_printf(MSG_DEBUG,
+ "PASN: Building frame 2: success; resp STA=" MACSTR,
+ MAC2STR(sta->addr));
+
+ ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+ NULL, 0, 0);
+ if (ret)
+ wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+
+ wpabuf_free(buf);
+ return ret;
+fail:
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+ wpabuf_free(buf);
+ return -1;
+}
+
+
+static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn_data;
+ struct wpa_pasn_params_data pasn_params;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
+ const u8 *cached_pmk = NULL;
+ size_t cached_pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
+#endif /* CONFIG_IEEE80211R_AP */
+ struct wpabuf *wrapped_data = NULL, *secret = NULL;
+ const int *groups = hapd->conf->pasn_groups;
+ static const int default_groups[] = { 19, 0 };
+ u16 status = WLAN_STATUS_SUCCESS;
+ int ret, inc_y;
+ bool derive_keys;
+ u32 i;
+
+ if (!groups)
+ groups = default_groups;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
+ !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ sta->pasn->akmp = rsn_data.key_mgmt;
+ sta->pasn->cipher = rsn_data.pairwise_cipher;
+
+ if (hapd->conf->force_kdk_derivation ||
+ ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SECURE_LTF)))
+ sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
+ else
+ sta->pasn->kdk_len = 0;
+ wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len);
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
+ ;
+
+ if (!pasn_params.group || groups[i] != pasn_params.group) {
+ wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
+ pasn_params.group);
+ status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto send_resp;
+ }
+
+ if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ if (pasn_params.comeback) {
+ wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
+
+ ret = check_comeback_token(hapd, sta->addr,
+ pasn_params.comeback,
+ pasn_params.comeback_len);
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ } else if (use_anti_clogging(hapd)) {
+ wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
+ handle_auth_pasn_comeback(hapd, sta, pasn_params.group);
+ ap_free_sta(hapd, sta);
+ return;
+ }
+
+ sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
+ if (!sta->pasn->ecdh) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ sta->pasn->group = pasn_params.group;
+
+ if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+ inc_y = 1;
+ } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+ pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+ inc_y = 0;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid first octet in pubkey=0x%x",
+ pasn_params.pubkey[0]);
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
+ pasn_params.pubkey + 1,
+ pasn_params.pubkey_len - 1);
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ derive_keys = true;
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_commit(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE commit");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Pending AS response");
+
+ /*
+ * With PASN/FILS, keys can be derived only after a
+ * response from the AS is processed.
+ */
+ derive_keys = false;
+ }
+#endif /* CONFIG_FILS */
+ }
+
+ sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ if (!derive_keys) {
+ wpa_printf(MSG_DEBUG, "PASN: Storing secret");
+ sta->pasn->secret = secret;
+ wpabuf_free(wrapped_data);
+ return;
+ }
+
+ if (rsn_data.num_pmkid) {
+ if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R_AP
+ wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
+
+ ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid,
+ pmk_r1, &pmk_r1_len, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed getting PMK-R1");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ cached_pmk = pmk_r1;
+ cached_pmk_len = pmk_r1_len;
+#else /* CONFIG_IEEE80211R_AP */
+ wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+#endif /* CONFIG_IEEE80211R_AP */
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid);
+ if (pmksa) {
+ cached_pmk = pmksa->pmk;
+ cached_pmk_len = pmksa->pmk_len;
+ }
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
+ }
+
+ ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
+ &pasn_params, wrapped_data, secret);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+send_resp:
+ ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Success handling transaction == 1");
+ }
+
+ wpabuf_free(secret);
+ wpabuf_free(wrapped_data);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_pasn_params_data pasn_params;
+ struct wpabuf *wrapped_data = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ int ret;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ goto fail;
+ }
+
+ /* Check that the MIC IE exists. Save it and zero out the memory. */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ if (!elems.mic || elems.mic_len != mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid MIC. Expecting len=%u", mic_len);
+ goto fail;
+ } else {
+ os_memcpy(mic, elems.mic, mic_len);
+ /* TODO: Clean this up.. Should not modify received frame
+ * buffer. */
+ os_memset((u8 *) elems.mic, 0, mic_len);
+ }
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ goto fail;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ goto fail;
+ }
+
+ if (pasn_params.pubkey || pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Public key should not be included");
+ goto fail;
+ }
+
+ /* Verify the MIC */
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ sta->addr, hapd->own_addr,
+ sta->pasn->hash, mic_len * 2,
+ (u8 *) &mgmt->u.auth,
+ len - offsetof(struct ieee80211_mgmt, u.auth),
+ out_mic);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+ if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+ goto fail;
+ }
+
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ goto fail;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_confirm(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE confirm");
+ wpabuf_free(wrapped_data);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Ignore wrapped data");
+ }
+ }
+#endif /* CONFIG_FILS */
+ wpabuf_free(wrapped_data);
+ }
+
+ wpa_printf(MSG_INFO,
+ "PASN: Success handling transaction == 3. Store PTK");
+
+ ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
+ &sta->pasn->ptk);
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u16 trans_seq, u16 status)
+{
+ if (hapd->conf->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_INFO, "PASN: RSN is not configured");
+ return;
+ }
+
+ wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
+ MAC2STR(sta->addr));
+
+ if (trans_seq == 1) {
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 1");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 1");
+ return;
+ }
+
+ sta->pasn = os_zalloc(sizeof(*sta->pasn));
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to allocate PASN context");
+ return;
+ }
+
+ handle_auth_pasn_1(hapd, sta, mgmt, len);
+ } else if (trans_seq == 3) {
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 3");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 3");
+ ap_free_sta_pasn(hapd, sta);
+ return;
+ }
+
+ handle_auth_pasn_3(hapd, sta, mgmt, len);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid transaction %u - ignore", trans_seq);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue)
@@ -2035,14 +3556,10 @@ static void handle_auth(struct hostapd_data *hapd,
int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
- char *identity = NULL;
- char *radius_cui = NULL;
u16 seq_ctrl;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2115,6 +3632,11 @@ static void handle_auth(struct hostapd_data *hapd,
hapd->conf->fils_dh_group &&
auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ (hapd->conf->wpa &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
+ auth_alg == WLAN_AUTH_PASN) ||
+#endif /* CONFIG_PASN */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -2124,6 +3646,9 @@ static void handle_auth(struct hostapd_data *hapd,
}
if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+#ifdef CONFIG_PASN
+ (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
+#endif /* CONFIG_PASN */
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
auth_transaction);
@@ -2193,10 +3718,8 @@ static void handle_auth(struct hostapd_data *hapd,
}
}
- res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
- &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
- 0);
+ res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info);
if (res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Authentication frame from " MACSTR
@@ -2247,6 +3770,15 @@ static void handle_auth(struct hostapd_data *hapd,
return;
}
#endif /* CONFIG_MESH */
+#ifdef CONFIG_PASN
+ if (auth_alg == WLAN_AUTH_PASN &&
+ (sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth: Existing station: " MACSTR,
+ MAC2STR(sta->addr));
+ return;
+ }
+#endif /* CONFIG_PASN */
} else {
#ifdef CONFIG_MESH
if (hapd->conf->mesh & MESH_ENABLED) {
@@ -2279,9 +3811,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_rssi = rssi;
#endif /* CONFIG_MBO */
- res = ieee802_11_set_radius_info(
- hapd, sta, res, session_timeout, acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui);
+ res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
if (res) {
wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2309,37 +3839,18 @@ static void handle_auth(struct hostapd_data *hapd,
* to allow the original connection work until the attempt can complete
* (re)association, so that unprotected Authentication frame cannot be
* used to bypass PMF protection.
+ *
+ * PASN authentication does not require adding/removing station to the
+ * driver so skip this flow in case of PASN authentication.
*/
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
- !(sta->added_unassoc)) {
- /*
- * If a station that is already associated to the AP, is trying
- * to authenticate again, remove the STA entry, in order to make
- * sure the STA PS state gets cleared and configuration gets
- * updated. To handle this, station's added_unassoc flag is
- * cleared once the station has completed association.
- */
- ap_sta_set_authorized(hapd, sta, 0);
- hostapd_drv_sta_remove(hapd, sta->addr);
- sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
- WLAN_STA_AUTHORIZED);
-
- if (hostapd_sta_add(hapd, sta->addr, 0, 0,
- sta->supported_rates,
- sta->supported_rates_len,
- 0, NULL, NULL, NULL, 0,
- sta->flags, 0, 0, 0, 0)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_NOTICE,
- "Could not add STA to kernel driver");
+ !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
+ if (ap_sta_re_add(hapd, sta) < 0) {
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
-
- sta->added_unassoc = 1;
}
switch (auth_alg) {
@@ -2352,6 +3863,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -2370,6 +3882,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
break;
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@@ -2420,16 +3933,20 @@ static void handle_auth(struct hostapd_data *hapd,
handle_auth_fils_finish);
return;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ case WLAN_AUTH_PASN:
+ handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
+ return;
+#endif /* CONFIG_PASN */
}
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
-
- reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
- auth_transaction + 1, resp, resp_ies,
- resp_ies_len, "handle-auth");
+ reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
+ auth_alg == WLAN_AUTH_SAE ?
+ auth_transaction : auth_transaction + 1,
+ resp, resp_ies, resp_ies_len,
+ "handle-auth");
if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
reply_res != WLAN_STATUS_SUCCESS)) {
@@ -2844,7 +4361,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
u16 status;
u8 *owe_buf, ie[256 * 2];
size_t ie_len = 0;
- int res;
+ enum wpa_validate_result res;
if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
@@ -2865,7 +4382,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, owe_dh, owe_dh_len);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -2916,11 +4433,39 @@ end:
#endif /* CONFIG_OWE */
-static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
struct ieee802_11_elems elems;
- u16 resp;
+ int resp;
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
@@ -2949,7 +4494,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -2960,7 +4504,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"mandatory HT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_HT;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac) {
@@ -2989,12 +4532,25 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities,
elems.he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ if (!(sta->flags & WLAN_STA_HE)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station does not support mandatory HE PHY - reject association");
+ return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
+ }
+ resp = copy_sta_he_6ghz_capab(hapd, sta,
+ elems.he_6ghz_band_cap);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
}
#endif /* CONFIG_IEEE80211AX */
@@ -3028,6 +4584,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
+ if (check_sa_query(hapd, sta, reassoc))
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
sta->flags |= WLAN_STA_WPS;
wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
@@ -3057,7 +4615,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
if (hapd->conf->wpa && wpa_ie) {
- int res;
+ enum wpa_validate_result res;
+
wpa_ie -= 2;
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
@@ -3073,39 +4632,21 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211W
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
+ if (check_sa_query(hapd, sta, reassoc))
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
- }
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -3150,6 +4691,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
MAC2STR(sta->addr), sta->auth_alg);
return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
}
+
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && !sta->sae->h2e &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SAE_H2E)) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_OWE
@@ -3167,7 +4719,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
dpp_pfs_free(sta->dpp_pfs);
sta->dpp_pfs = NULL;
- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ if (DPP_VERSION > 1 &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
elems.owe_dh) {
@@ -3194,7 +4747,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
pfs_fail:
#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr,
@@ -3204,7 +4756,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (elems.osen == NULL) {
@@ -3243,7 +4794,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
- if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_DEBUG,
"HS 2.0: PMF not negotiated by release %d station "
MACSTR, release, MAC2STR(sta->addr));
@@ -3290,6 +4842,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3303,9 +4856,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
+ res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "FILS: Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sta->wpa_sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
+ ocv_errorstr);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=fils-reassoc-req error=%s",
+ MAC2STR(sta->addr), ocv_errorstr);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
}
@@ -3348,7 +4912,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
reply.u.deauth.reason_code = host_to_le16(reason_code);
- if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send deauth: %s",
strerror(errno));
}
@@ -3404,10 +4968,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->ft_over_ds = 0;
}
-#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
@@ -3431,6 +4993,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
+ sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) {
@@ -3455,7 +5018,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc,
- const u8 *ies, size_t ies_len, int rssi)
+ const u8 *ies, size_t ies_len, int rssi,
+ int omit_rsnxe)
{
int send_len;
u8 *buf;
@@ -3506,6 +5070,9 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+ /* Radio measurement capabilities */
+ p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_MBO
if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
rssi != 0) {
@@ -3522,7 +5089,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p,
- sta->auth_alg, ies, ies_len);
+ sta->auth_alg, ies, ies_len,
+ omit_rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG,
"FT: Failed to write AssocResp IEs");
@@ -3549,18 +5117,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
ies, ies_len);
#endif /* CONFIG_OWE */
-#ifdef CONFIG_IEEE80211W
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
u32 nsts = 0, sta_nsts;
if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
@@ -3583,11 +5148,12 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
+ p = hostapd_eid_he_6ghz_band_cap(hapd, p);
}
#endif /* CONFIG_IEEE80211AX */
@@ -3604,10 +5170,29 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->rsnxe_override_ft &&
+ buf + buflen - p >=
+ (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
+ sta && sta->auth_alg == WLAN_AUTH_FT) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
+ os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
+ wpabuf_len(hapd->conf->rsnxe_override_ft));
+ p += wpabuf_len(hapd->conf->rsnxe_override_ft);
+ goto rsnxe_done;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!omit_rsnxe)
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxe_done:
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
@@ -3628,7 +5213,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
@@ -3733,7 +5318,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FILS */
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3748,12 +5333,12 @@ done:
#ifdef CONFIG_OWE
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
- u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+ u8 *owe_buf, size_t owe_buf_len, u16 *status)
{
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->own_ie_override) {
wpa_printf(MSG_DEBUG, "OWE: Using IE override");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
}
@@ -3763,18 +5348,18 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
if (sta->owe_pmk && sta->external_dh_updated) {
wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
- *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
- if (*reason != WLAN_STATUS_SUCCESS)
+ *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*status != WLAN_STATUS_SUCCESS)
return NULL;
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
@@ -3785,7 +5370,7 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
- *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
return owe_buf;
}
@@ -3820,7 +5405,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req,
- sta->fils_pending_assoc_req_len, 0);
+ sta->fils_pending_assoc_req_len, 0, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -3860,17 +5445,16 @@ static void handle_assoc(struct hostapd_data *hapd,
int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS, reply_res;
+ int resp = WLAN_STATUS_SUCCESS;
+ u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
#ifdef CONFIG_FILS
int delay_assoc = 0;
#endif /* CONFIG_FILS */
+ int omit_rsnxe = 0;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -3947,13 +5531,11 @@ static void handle_assoc(struct hostapd_data *hapd,
hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211AD) {
int acl_res;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
+ struct radius_sta info;
- acl_res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout, &acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui, 0);
+ acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+ (const u8 *) mgmt,
+ len, &info);
if (acl_res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Association Request frame from "
@@ -3978,9 +5560,7 @@ static void handle_assoc(struct hostapd_data *hapd,
}
acl_res = ieee802_11_set_radius_info(
- hapd, sta, acl_res, session_timeout,
- acct_interim_interval, &vlan_id, &psk,
- &identity, &radius_cui);
+ hapd, sta, acl_res, &info);
if (acl_res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
@@ -4087,6 +5667,7 @@ static void handle_assoc(struct hostapd_data *hapd,
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
+ omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -4139,9 +5720,7 @@ static void handle_assoc(struct hostapd_data *hapd,
ieee802_11_set_beacons(hapd->iface);
}
-#ifdef CONFIG_IEEE80211N
update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -4150,7 +5729,6 @@ static void handle_assoc(struct hostapd_data *hapd,
*/
sta->flags |= WLAN_STA_ASSOC_REQ_OK;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
"SA Query procedure", reassoc ? "re" : "");
@@ -4161,7 +5739,6 @@ static void handle_assoc(struct hostapd_data *hapd,
* trying to associate.
*/
}
-#endif /* CONFIG_IEEE80211W */
/* Make sure that the previously registered inactivity timer will not
* remove the STA immediately. */
@@ -4183,9 +5760,6 @@ static void handle_assoc(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
/*
* In case of a successful response, add the station to the driver.
@@ -4246,12 +5820,13 @@ static void handle_assoc(struct hostapd_data *hapd,
}
#endif /* CONFIG_FILS */
- reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left, rssi);
+ if (resp >= 0)
+ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
+ pos, left, rssi, omit_rsnxe);
os_free(tmp);
/*
- * Remove the station in case tranmission of a success response fails
+ * Remove the station in case transmission of a success response fails
* (the STA was added associated to the driver) or if the station was
* previously added unassociated.
*/
@@ -4288,6 +5863,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
ap_sta_set_authorized(hapd, sta, 0);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@@ -4342,6 +5918,9 @@ static void handle_deauth(struct hostapd_data *hapd,
" reason_code=%d",
MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
+ /* Clear the PTKSA cache entries for PASN */
+ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
+
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
@@ -4354,6 +5933,7 @@ static void handle_deauth(struct hostapd_data *hapd,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -4386,13 +5966,11 @@ static void handle_beacon(struct hostapd_data *hapd,
}
-#ifdef CONFIG_IEEE80211W
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
category != WLAN_ACTION_HT;
}
-#endif /* CONFIG_IEEE80211W */
static int handle_action(struct hostapd_data *hapd,
@@ -4426,7 +6004,6 @@ static int handle_action(struct hostapd_data *hapd,
return 0;
}
-#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
robust_action_frame(mgmt->u.action.category)) {
@@ -4436,7 +6013,6 @@ static int handle_action(struct hostapd_data *hapd,
"an MFP STA");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
if (sta) {
u16 fc = le_to_host16(mgmt->frame_control);
@@ -4470,11 +6046,9 @@ static int handle_action(struct hostapd_data *hapd,
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
-#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
ieee802_11_sa_query_action(hapd, mgmt, len);
return 1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4491,14 +6065,12 @@ static int handle_action(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
-#ifdef CONFIG_IEEE80211N
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
hostapd_2040_coex_action(hapd, mgmt, len);
return 1;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_DPP
if (len >= IEEE80211_HDRLEN + 6 &&
mgmt->u.action.u.vs_public_action.action ==
@@ -4581,7 +6153,7 @@ static int handle_action(struct hostapd_data *hapd,
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
"Action frame");
}
@@ -4593,6 +6165,31 @@ static int handle_action(struct hostapd_data *hapd,
/**
+ * notify_mgmt_frame - Notify of Management frames on the control interface
+ * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
+ * sent to)
+ * @buf: Management frame data (starting from the IEEE 802.11 header)
+ * @len: Length of frame data in octets
+ *
+ * Notify the control interface of any received Management frame.
+ */
+static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
+ size_t len)
+{
+
+ int hex_len = len * 2 + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
+ AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
+ os_free(hex);
+ }
+}
+
+
+/**
* ieee802_11_mgmt - process incoming IEEE 802.11 management frames
* @hapd: hostapd BSS data structure (the BSS to which the management frame was
* sent to)
@@ -4626,6 +6223,18 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+ if (is_multicast_ether_addr(mgmt->sa) ||
+ is_zero_ether_addr(mgmt->sa) ||
+ os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Do not process any frames with unexpected/invalid SA so that
+ * we do not add any state for unexpected STA addresses or end
+ * up sending out frames to unexpected destination. */
+ wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
+ " in received frame - ignore this frame silently",
+ MAC2STR(mgmt->sa));
+ return 0;
+ }
+
if (stype == WLAN_FC_STYPE_BEACON) {
handle_beacon(hapd, mgmt, len, fi);
return 1;
@@ -4646,6 +6255,11 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
return 0;
}
+ if (hapd->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
+ return 1;
+ }
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
handle_probe_req(hapd, mgmt, len, ssi_signal);
@@ -4665,6 +6279,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
+ if (hapd->conf->notify_mgmt_frames)
+ notify_mgmt_frame(hapd, buf, len);
+
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
@@ -4712,6 +6329,7 @@ static void handle_auth_cb(struct hostapd_data *hapd,
{
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ bool success_status;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -4721,6 +6339,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
return;
}
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
+ auth_alg = 0;
+ auth_transaction = 0;
+ status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
@@ -4732,12 +6359,6 @@ static void handle_auth_cb(struct hostapd_data *hapd,
goto fail;
}
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
- (unsigned long) len);
- goto fail;
- }
-
if (status_code == WLAN_STATUS_SUCCESS &&
((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
@@ -4750,7 +6371,12 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
fail:
- if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ success_status = status_code == WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_SAE
+ if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+#endif /* CONFIG_SAE */
+ if (!success_status && sta->added_unassoc) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -4761,6 +6387,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
struct sta_info *sta,
char *ifname_wds)
{
+#ifdef CONFIG_WEP
int i;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
@@ -4770,14 +6397,18 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
for (i = 0; i < 4; i++) {
if (ssid->wep.key[i] &&
hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
- i == ssid->wep.idx, NULL, 0,
- ssid->wep.key[i], ssid->wep.len[i])) {
+ 0, i == ssid->wep.idx, NULL, 0,
+ ssid->wep.key[i], ssid->wep.len[i],
+ i == ssid->wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING,
"Could not set WEP keys for WDS interface; %s",
ifname_wds);
break;
}
}
+#endif /* CONFIG_WEP */
}
@@ -4856,9 +6487,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
else
mlme_associate_indication(hapd, sta);
-#ifdef CONFIG_IEEE80211W
sta->sa_query_timed_out = 0;
-#endif /* CONFIG_IEEE80211W */
if (sta->eapol_sm == NULL) {
/*
@@ -5251,8 +6880,10 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (is_multicast_ether_addr(src)) {
- /* Broadcast bit set in SA?! Ignore the frame silently. */
+ if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
+ os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
+ * silently. */
return;
}
@@ -5275,4 +6906,169 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_channel_data *chan;
+ int dfs, i;
+ u8 channel, tx_pwr_count, local_pwr_constraint;
+ int max_tx_power;
+ u8 tx_pwr;
+
+ if (!mode)
+ return eid;
+
+ if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+ return eid;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == iface->freq)
+ break;
+ }
+ if (i == mode->num_channels)
+ return eid;
+
+ switch (hostapd_get_oper_chwidth(iconf)) {
+ case CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel == 0) {
+ /* Max Transmit Power count = 0 (20 MHz) */
+ tx_pwr_count = 0;
+ } else {
+ /* Max Transmit Power count = 1 (20, 40 MHz) */
+ tx_pwr_count = 1;
+ }
+ break;
+ case CHANWIDTH_80MHZ:
+ /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+ tx_pwr_count = 2;
+ break;
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+ tx_pwr_count = 3;
+ break;
+ default:
+ return eid;
+ }
+
+ /*
+ * Below local_pwr_constraint logic is referred from
+ * hostapd_eid_pwr_constraint.
+ *
+ * Check if DFS is required by regulatory.
+ */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0)
+ dfs = 0;
+
+ /*
+ * In order to meet regulations when TPC is not implemented using
+ * a transmit power that is below the legal maximum (including any
+ * mitigation factor) should help. In this case, indicate 3 dB below
+ * maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = (dfs == 0) ? 0 : 3;
+ else
+ local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+ chan = &mode->channels[i];
+ max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+ /*
+ * Local Maximum Transmit power is encoded as two's complement
+ * with a 0.5 dB step.
+ */
+ max_tx_power *= 2; /* in 0.5 dB steps */
+ if (max_tx_power > 127) {
+ /* 63.5 has special meaning of 63.5 dBm or higher */
+ max_tx_power = 127;
+ }
+ if (max_tx_power < -128)
+ max_tx_power = -128;
+ if (max_tx_power < 0)
+ tx_pwr = 0x80 + max_tx_power + 128;
+ else
+ tx_pwr = max_tx_power;
+
+ *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
+ *eid++ = 2 + tx_pwr_count;
+
+ /*
+ * Max Transmit Power count and
+ * Max Transmit Power units = 0 (EIRP)
+ */
+ *eid++ = tx_pwr_count;
+
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ (!hapd->cs_freq_params.vht_enabled &&
+ !hapd->cs_freq_params.he_enabled))
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa/src/ap/ieee802_11.h b/contrib/wpa/src/ap/ieee802_11.h
index b8453c992a9c..ea8c60846936 100644
--- a/contrib/wpa/src/ap/ieee802_11.h
+++ b/contrib/wpa/src/ap/ieee802_11.h
@@ -16,8 +16,7 @@ struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -50,9 +49,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
@@ -63,6 +63,7 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -95,6 +96,10 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len);
+u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *he_6ghz_capab);
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -162,7 +167,7 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len);
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
- u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+ u8 *owe_buf, size_t owe_buf_len, u16 *status);
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
@@ -180,17 +185,14 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
-int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
- int is_probe_req);
+
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
#endif /* IEEE802_11_H */
diff --git a/contrib/wpa/src/ap/ieee802_11_auth.c b/contrib/wpa/src/ap/ieee802_11_auth.c
index 931d4d0659c3..783ee6dea96b 100644
--- a/contrib/wpa/src/ap/ieee802_11_auth.c
+++ b/contrib/wpa/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@ struct hostapd_cached_radius_acl {
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
- u32 session_timeout;
- u32 acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk;
- char *identity;
- char *radius_cui;
+ struct radius_sta info;
};
@@ -54,9 +49,9 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
- os_free(e->identity);
- os_free(e->radius_cui);
- hostapd_free_psk_list(e->psk);
+ os_free(e->info.identity);
+ os_free(e->info.radius_cui);
+ hostapd_free_psk_list(e->info.psk);
os_free(e);
}
@@ -73,25 +68,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
}
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
- struct hostapd_sta_wpa_psk_short *src)
-{
- if (!psk)
- return;
-
- if (src)
- src->ref++;
-
- *psk = src;
-}
-
-
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
- u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ struct radius_sta *out)
{
struct hostapd_cached_radius_acl *entry;
struct os_reltime now;
@@ -105,27 +83,8 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout = entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- copy_psk_list(psk, entry->psk);
- if (identity) {
- if (entry->identity)
- *identity = os_strdup(entry->identity);
- else
- *identity = NULL;
- }
- if (radius_cui) {
- if (entry->radius_cui)
- *radius_cui = os_strdup(entry->radius_cui);
- else
- *radius_cui = NULL;
- }
+ *out = entry->info;
+
return entry->accepted;
}
@@ -238,42 +197,28 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * @psk: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from
+ * RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.radius_cui: Buffer for returning CUI (from RADIUS)
* @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
- * The caller is responsible for freeing the returned *identity and *radius_cui
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req)
{
int res;
- if (session_timeout)
- *session_timeout = 0;
- if (acct_interim_interval)
- *acct_interim_interval = 0;
- if (vlan_id)
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- if (psk)
- *psk = NULL;
- if (identity)
- *identity = NULL;
- if (radius_cui)
- *radius_cui = NULL;
-
- res = hostapd_check_acl(hapd, addr, vlan_id);
+ os_memset(out, 0, sizeof(*out));
+
+ res = hostapd_check_acl(hapd, addr, &out->vlan_id);
if (res != HOSTAPD_ACL_PENDING)
return res;
@@ -290,12 +235,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
};
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = NULL;
+ os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
/* Check whether ACL cache has an entry for this station */
- res = hostapd_acl_cache_get(hapd, addr, session_timeout,
- acct_interim_interval, vlan_id, psk,
- identity, radius_cui);
+ res = hostapd_acl_cache_get(hapd, addr, out);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -307,14 +250,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
- if (identity) {
- os_free(*identity);
- *identity = NULL;
- }
- if (radius_cui) {
- os_free(*radius_cui);
- *radius_cui = NULL;
- }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -488,8 +423,8 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
passphraselen);
psk->is_passphrase = 1;
}
- psk->next = cache->psk;
- cache->psk = psk;
+ psk->next = cache->info.psk;
+ cache->info.psk = psk;
psk = NULL;
}
skip:
@@ -518,6 +453,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
+ struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
@@ -555,65 +491,66 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+ info = &cache->info;
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
- &cache->session_timeout) == 0)
+ &info->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
- &cache->acct_interim_interval) == 0 &&
- cache->acct_interim_interval < 60) {
+ &info->acct_interim_interval) == 0 &&
+ info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
- cache->acct_interim_interval,
+ info->acct_interim_interval,
MAC2STR(query->addr));
- cache->acct_interim_interval = 0;
+ info->acct_interim_interval = 0;
}
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
- cache->vlan_id.notempty = !!radius_msg_get_vlanid(
- msg, &cache->vlan_id.untagged,
- MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
+ info->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &info->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
- cache->identity = os_zalloc(len + 1);
- if (cache->identity)
- os_memcpy(cache->identity, buf, len);
+ info->identity = os_zalloc(len + 1);
+ if (info->identity)
+ os_memcpy(info->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
- cache->radius_cui = os_zalloc(len + 1);
- if (cache->radius_cui)
- os_memcpy(cache->radius_cui, buf, len);
+ info->radius_cui = os_zalloc(len + 1);
+ if (info->radius_cui)
+ os_memcpy(info->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->psk)
+ !info->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+ if (info->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
- cache->vlan_id.untagged,
- cache->vlan_id.tagged[0] ? "+" : "");
- os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+ info->vlan_id.untagged,
+ info->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id.notempty)
+ !info->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -622,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- cache->session_timeout);
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@@ -685,6 +622,19 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
}
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
+}
+
+
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
if (psk && psk->ref) {
diff --git a/contrib/wpa/src/ap/ieee802_11_auth.h b/contrib/wpa/src/ap/ieee802_11_auth.h
index 5aece5183c69..9410f55c5807 100644
--- a/contrib/wpa/src/ap/ieee802_11_auth.h
+++ b/contrib/wpa/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+struct radius_sta {
+ u32 session_timeout;
+ u32 acct_interim_interval;
+ struct vlan_description vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk;
+ char *identity;
+ char *radius_cui;
+};
+
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src);
#endif /* IEEE802_11_AUTH_H */
diff --git a/contrib/wpa/src/ap/ieee802_11_he.c b/contrib/wpa/src/ap/ieee802_11_he.c
index a51f3fcb0eae..cbe5e639588f 100644
--- a/contrib/wpa/src/ap/ieee802_11_he.c
+++ b/contrib/wpa/src/ap/ieee802_11_he.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@@ -44,6 +45,41 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
}
+static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
+{
+ u8 sz = 4;
+
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
+ sz += 4;
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ sz += 4;
+
+ return sz;
+}
+
+
+static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
+{
+ struct ieee80211_he_capabilities *cap;
+ size_t cap_len;
+
+ cap = (struct ieee80211_he_capabilities *) buf;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+
+ return len != cap_len;
+}
+
+
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode)
{
@@ -51,12 +87,12 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
u8 *pos = eid;
- u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
+ u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
if (!mode)
return eid;
- ie_size = sizeof(struct ieee80211_he_capabilities);
+ ie_size = sizeof(*cap) - sizeof(cap->optional);
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
mode->he_capab[opmode].phy_cap);
@@ -74,7 +110,6 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
case CHANWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
- mcs_nss_size += 4;
break;
}
@@ -136,6 +171,9 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (!hapd->iface->current_mode)
return eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ oper_size += 5;
+
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
@@ -154,9 +192,12 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
params |= (hapd->iface->conf->he_op.he_rts_threshold <<
HE_OPERATION_RTS_THRESHOLD_OFFSET);
- if (hapd->iface->conf->he_op.he_bss_color)
- params |= (hapd->iface->conf->he_op.he_bss_color <<
- HE_OPERATION_BSS_COLOR_OFFSET);
+ if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ params |= HE_OPERATION_BSS_COLOR_DISABLED;
+ if (hapd->iface->conf->he_op.he_bss_color_partial)
+ params |= HE_OPERATION_BSS_COLOR_PARTIAL;
+ params |= hapd->iface->conf->he_op.he_bss_color <<
+ HE_OPERATION_BSS_COLOR_OFFSET;
/* HE minimum required basic MCS and NSS for STAs */
oper->he_mcs_nss_set =
@@ -164,9 +205,49 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
/* TODO: conditional MaxBSSID Indicator subfield */
- oper->he_oper_params = host_to_le32(params);
+ pos += 6; /* skip the fixed part */
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+ u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+
+ if (!seg0)
+ seg0 = hapd->iconf->channel;
+
+ params |= HE_OPERATION_6GHZ_OPER_INFO;
+
+ /* 6 GHz Operation Information field
+ * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
+ * Figure 9-788k
+ */
+ *pos++ = hapd->iconf->channel; /* Primary Channel */
+
+ /* Control: Channel Width */
+ if (seg1)
+ *pos++ = 3;
+ else
+ *pos++ = center_idx_to_bw_6ghz(seg0);
+
+ /* Channel Center Freq Seg0/Seg1 */
+ if (hapd->iconf->he_oper_chwidth == 2) {
+ /*
+ * Seg 0 indicates the channel center frequency index of
+ * the 160 MHz channel.
+ */
+ seg1 = seg0;
+ if (hapd->iconf->channel < seg0)
+ seg0 -= 8;
+ else
+ seg0 += 8;
+ }
- pos += oper_size;
+ *pos++ = seg0;
+ *pos++ = seg1;
+ /* Minimum Rate */
+ *pos++ = 6; /* TODO: what should be set here? */
+ }
+
+ oper->he_oper_params = host_to_le32(params);
return pos;
}
@@ -238,6 +319,11 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ spr_param += 8;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
pos += 18;
}
@@ -245,6 +331,46 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_config *conf = hapd->iface->conf;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct he_capabilities *he_cap;
+ struct ieee80211_he_6ghz_band_cap *cap;
+ u16 capab;
+ u8 *pos;
+
+ if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
+ !is_6ghz_freq(hapd->iface->freq))
+ return eid;
+
+ he_cap = &mode->he_capab[IEEE80211_MODE_AP];
+ capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
+ capab |= (conf->he_6ghz_max_ampdu_len_exp <<
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
+ capab |= (conf->he_6ghz_max_mpdu <<
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
+ capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
+ if (conf->he_6ghz_rx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
+ if (conf->he_6ghz_tx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
+
+ pos = eid;
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*cap);
+ *pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
+
+ cap = (struct ieee80211_he_6ghz_band_cap *) pos;
+ cap->capab = host_to_le16(capab);
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
void hostapd_get_he_capab(struct hostapd_data *hapd,
const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_he_cap,
@@ -323,8 +449,10 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len)
{
- if (!he_capab || !hapd->iconf->ieee80211ax ||
+ if (!he_capab || !(sta->flags & WLAN_STA_WMM) ||
+ !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
+ ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
sta->flags &= ~WLAN_STA_HE;
os_free(sta->he_capab);
@@ -346,3 +474,46 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+
+
+u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *he_6ghz_capab)
+{
+ if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
+ hapd->conf->disable_11ax ||
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
+ sta->flags &= ~WLAN_STA_6GHZ;
+ os_free(sta->he_6ghz_capab);
+ sta->he_6ghz_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->he_6ghz_capab) {
+ sta->he_6ghz_capab =
+ os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
+ if (!sta->he_6ghz_capab)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_6GHZ;
+ os_memcpy(sta->he_6ghz_capab, he_6ghz_capab,
+ sizeof(struct ieee80211_he_6ghz_band_cap));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode)
+{
+ u8 *mac_cap;
+
+ if (!hapd->iface->current_mode ||
+ !hapd->iface->current_mode->he_capab[mode].he_supported)
+ return 0;
+
+ mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
+
+ return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
+ hapd->iface->conf->he_op.he_twt_responder;
+}
diff --git a/contrib/wpa/src/ap/ieee802_11_ht.c b/contrib/wpa/src/ap/ieee802_11_ht.c
index 214855dccb8c..59ecbdce7bf1 100644
--- a/contrib/wpa/src/ap/ieee802_11_ht.c
+++ b/contrib/wpa/src/ap/ieee802_11_ht.c
@@ -27,7 +27,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
- hapd->conf->disable_11n)
+ hapd->conf->disable_11n || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_CAP;
@@ -84,7 +84,8 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@@ -108,32 +109,9 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
}
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
-{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.sec_channel_offset)
- return eid;
-
- if (hapd->cs_freq_params.sec_channel_offset == -1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->cs_freq_params.sec_channel_offset == 1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
- else
- return eid;
-
- *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
- *eid++ = 1;
- *eid++ = sec_ch;
-
- return eid;
-}
-
-
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
diff --git a/contrib/wpa/src/ap/ieee802_11_shared.c b/contrib/wpa/src/ap/ieee802_11_shared.c
index 707381ffe709..4bff9e591883 100644
--- a/contrib/wpa/src/ap/ieee802_11_shared.c
+++ b/contrib/wpa/src/ap/ieee802_11_shared.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
@@ -19,8 +20,6 @@
#include "ieee802_11.h"
-#ifdef CONFIG_IEEE80211W
-
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
@@ -74,6 +73,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Request");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_req);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -114,7 +123,8 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
os_free(mgmt);
@@ -152,6 +162,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Response");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_resp);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -195,7 +215,8 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
os_free(resp);
@@ -220,6 +241,12 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
(unsigned long) len);
return;
}
+ if (is_multicast_ether_addr(mgmt->da)) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11: Ignore group-addressed SA Query frame (A1=" MACSTR " A2=" MACSTR ")",
+ MAC2STR(mgmt->da), MAC2STR(mgmt->sa));
+ return;
+ }
sta = ap_get_sta(hapd, sa);
@@ -254,14 +281,21 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
return;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=saquery%s error=%s",
+ MAC2STR(sa),
+ action_type == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
+ if (sta)
+ sta->post_csa_sa_query = 0;
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return;
}
@@ -304,8 +338,6 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
ap_sta_stop_sa_query(hapd, sta);
}
-#endif /* CONFIG_IEEE80211W */
-
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
@@ -379,6 +411,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
*pos |= 0x01;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ *pos |= 0x40; /* Bit 78 - TWT responder */
+#endif /* CONFIG_IEEE80211AX */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -394,6 +431,18 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
+ break;
+ case 11: /* Bits 88-95 */
+#ifdef CONFIG_SAE_PK
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ *pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
+#endif /* CONFIG_SAE_PK */
break;
}
}
@@ -402,48 +451,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- u8 len = 0, i;
-
- if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
- len = 5;
- if (len < 4 && hapd->conf->interworking)
- len = 4;
- if (len < 3 && hapd->conf->wnm_sleep_mode)
- len = 3;
- if (len < 1 && hapd->iconf->obss_interval)
- len = 1;
- if (len < 7 && hapd->conf->ssid.utf8_ssid)
- len = 7;
- if (len < 9 &&
- (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
- len = 9;
-#ifdef CONFIG_WNM_AP
- if (len < 4)
- len = 4;
-#endif /* CONFIG_WNM_AP */
-#ifdef CONFIG_HS20
- if (hapd->conf->hs20 && len < 6)
- len = 6;
-#endif /* CONFIG_HS20 */
-#ifdef CONFIG_MBO
- if (hapd->conf->mbo_enabled && len < 6)
- len = 6;
-#endif /* CONFIG_MBO */
-#ifdef CONFIG_FILS
- if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
- !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
- len = 10;
-#endif /* CONFIG_FILS */
-#ifdef CONFIG_SAE
- if (len < 11 && hapd->conf->wpa &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
- hostapd_sae_pw_id_in_use(hapd->conf))
- len = 11;
-#endif /* CONFIG_SAE */
+ u8 len = EXT_CAPA_MAX_LEN, i;
+
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
- if (len == 0)
- return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
@@ -454,6 +465,11 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos &= ~hapd->iface->extended_capa_mask[i];
*pos |= hapd->iface->extended_capa[i];
}
+
+ if (i < EXT_CAPA_MAX_LEN) {
+ *pos &= ~hapd->conf->ext_capa_mask[i];
+ *pos |= hapd->conf->ext_capa[i];
+ }
}
while (len > 0 && eid[1 + len] == 0) {
@@ -854,6 +870,35 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
}
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ if (hapd->conf->dpp_configurator_connectivity)
+ return 6;
+#endif /* CONFIG_DPP2 */
+ return 0;
+}
+
+
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+
+#ifdef CONFIG_DPP2
+ if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+ return pos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = DPP_CC_OUI_TYPE;
+#endif /* CONFIG_DPP2 */
+
+ return pos;
+}
+
+
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes,
size_t supp_op_classes_len)
@@ -1000,3 +1045,51 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
return 0;
}
#endif /* CONFIG_OCV */
+
+
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+ bool sae_pk = false;
+ u16 capab = 0;
+ size_t flen;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN))
+ return eid;
+
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+#endif /* CONFIG_SAE_PK */
+
+ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ (hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
+ hapd->conf->sae_pwe != 3) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (len < 2 + flen || !capab)
+ return eid; /* no supported extended RSN capabilities */
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
+
+ return pos;
+}
diff --git a/contrib/wpa/src/ap/ieee802_11_vht.c b/contrib/wpa/src/ap/ieee802_11_vht.c
index 269345fbf85b..828f0abb5aad 100644
--- a/contrib/wpa/src/ap/ieee802_11_vht.c
+++ b/contrib/wpa/src/ap/ieee802_11_vht.c
@@ -26,7 +26,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!mode)
+ if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
@@ -76,6 +76,9 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ return eid;
+
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@@ -164,176 +167,11 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
-{
- u8 bw, chan1, chan2 = 0;
- int freq1;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.vht_enabled)
- return eid;
-
- /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
- switch (hapd->cs_freq_params.bandwidth) {
- case 40:
- bw = 0;
- break;
- case 80:
- /* check if it's 80+80 */
- if (!hapd->cs_freq_params.center_freq2)
- bw = 1;
- else
- bw = 3;
- break;
- case 160:
- bw = 2;
- break;
- default:
- /* not valid VHT bandwidth or not in CSA */
- return eid;
- }
-
- freq1 = hapd->cs_freq_params.center_freq1 ?
- hapd->cs_freq_params.center_freq1 :
- hapd->cs_freq_params.freq;
- if (ieee80211_freq_to_chan(freq1, &chan1) !=
- HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- if (hapd->cs_freq_params.center_freq2 &&
- ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
- &chan2) != HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
- *eid++ = 5; /* Length of Channel Switch Wrapper */
- *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
- *eid++ = bw; /* New Channel Width */
- *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
- *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
-
- return eid;
-}
-
-
-u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
-{
- struct hostapd_iface *iface = hapd->iface;
- struct hostapd_config *iconf = iface->conf;
- struct hostapd_hw_modes *mode = iface->current_mode;
- struct hostapd_channel_data *chan;
- int dfs, i;
- u8 channel, tx_pwr_count, local_pwr_constraint;
- int max_tx_power;
- u8 tx_pwr;
-
- if (!mode)
- return eid;
-
- if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
- return eid;
-
- for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].freq == iface->freq)
- break;
- }
- if (i == mode->num_channels)
- return eid;
-
- switch (iface->conf->vht_oper_chwidth) {
- case CHANWIDTH_USE_HT:
- if (iconf->secondary_channel == 0) {
- /* Max Transmit Power count = 0 (20 MHz) */
- tx_pwr_count = 0;
- } else {
- /* Max Transmit Power count = 1 (20, 40 MHz) */
- tx_pwr_count = 1;
- }
- break;
- case CHANWIDTH_80MHZ:
- /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
- tx_pwr_count = 2;
- break;
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
- /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
- tx_pwr_count = 3;
- break;
- default:
- return eid;
- }
-
- /*
- * Below local_pwr_constraint logic is referred from
- * hostapd_eid_pwr_constraint.
- *
- * Check if DFS is required by regulatory.
- */
- dfs = hostapd_is_dfs_required(hapd->iface);
- if (dfs < 0)
- dfs = 0;
-
- /*
- * In order to meet regulations when TPC is not implemented using
- * a transmit power that is below the legal maximum (including any
- * mitigation factor) should help. In this case, indicate 3 dB below
- * maximum allowed transmit power.
- */
- if (hapd->iconf->local_pwr_constraint == -1)
- local_pwr_constraint = (dfs == 0) ? 0 : 3;
- else
- local_pwr_constraint = hapd->iconf->local_pwr_constraint;
-
- /*
- * A STA that is not an AP shall use a transmit power less than or
- * equal to the local maximum transmit power level for the channel.
- * The local maximum transmit power can be calculated from the formula:
- * local max TX pwr = max TX pwr - local pwr constraint
- * Where max TX pwr is maximum transmit power level specified for
- * channel in Country element and local pwr constraint is specified
- * for channel in this Power Constraint element.
- */
- chan = &mode->channels[i];
- max_tx_power = chan->max_tx_power - local_pwr_constraint;
-
- /*
- * Local Maximum Transmit power is encoded as two's complement
- * with a 0.5 dB step.
- */
- max_tx_power *= 2; /* in 0.5 dB steps */
- if (max_tx_power > 127) {
- /* 63.5 has special meaning of 63.5 dBm or higher */
- max_tx_power = 127;
- }
- if (max_tx_power < -128)
- max_tx_power = -128;
- if (max_tx_power < 0)
- tx_pwr = 0x80 + max_tx_power + 128;
- else
- tx_pwr = max_tx_power;
-
- *eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
- *eid++ = 2 + tx_pwr_count;
-
- /*
- * Max Transmit Power count and
- * Max Transmit Power units = 0 (EIRP)
- */
- *eid++ = tx_pwr_count;
-
- for (i = 0; i <= tx_pwr_count; i++)
- *eid++ = tx_pwr;
-
- return eid;
-}
-
-
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
- if (!vht_capab ||
+ if (!vht_capab || !(sta->flags & WLAN_STA_WMM) ||
!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
@@ -422,7 +260,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- if (!hapd->iface->current_mode)
+ /* Vendor VHT is applicable only to 2.4 GHz */
+ if (!hapd->iface->current_mode ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/contrib/wpa/src/ap/ieee802_1x.c b/contrib/wpa/src/ap/ieee802_1x.c
index e0614710f6c3..753c88335da7 100644
--- a/contrib/wpa/src/ap/ieee802_1x.c
+++ b/contrib/wpa/src/ap/ieee802_1x.c
@@ -58,10 +58,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
len = sizeof(*xhdr) + datalen;
buf = os_zalloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "malloc() failed for "
- "ieee802_1x_send(len=%lu)",
- (unsigned long) len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)",
+ __func__, (unsigned long) len);
return;
}
@@ -138,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@@ -152,12 +152,12 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
size_t len, ekey_len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
len = sizeof(*key) + key_len;
buf = os_zalloc(sizeof(*hdr) + len);
- if (buf == NULL)
+ if (!buf)
return;
hdr = (struct ieee802_1x_hdr *) buf;
@@ -198,16 +198,16 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
* MSK[32..63] is used to sign the message. */
- if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
- wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
- "and signing EAPOL-Key");
+ if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) {
+ wpa_printf(MSG_ERROR,
+ "No eapKeyData available for encrypting and signing EAPOL-Key");
os_free(buf);
return;
}
os_memcpy((u8 *) (key + 1), key_data, key_len);
ekey_len = sizeof(key->key_iv) + 32;
ekey = os_malloc(ekey_len);
- if (ekey == NULL) {
+ if (!ekey) {
wpa_printf(MSG_ERROR, "Could not encrypt key");
os_free(buf);
return;
@@ -244,7 +244,7 @@ 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;
- if (sm == NULL || !sm->eap_if->eapKeyData)
+ if (!sm || !sm->eap_if->eapKeyData)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
@@ -265,12 +265,13 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
if (hapd->conf->individual_wep_key_len > 0) {
u8 *ikey;
+
ikey = os_malloc(hapd->conf->individual_wep_key_len);
- if (ikey == NULL ||
+ if (!ikey ||
random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
{
- wpa_printf(MSG_ERROR, "Could not generate random "
- "individual WEP key.");
+ wpa_printf(MSG_ERROR,
+ "Could not generate random individual WEP key");
os_free(ikey);
return;
}
@@ -284,10 +285,11 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
- sta->addr, 0, 1, NULL, 0, ikey,
- hapd->conf->individual_wep_key_len)) {
- wpa_printf(MSG_ERROR, "Could not set individual WEP "
- "encryption.");
+ sta->addr, 0, 0, 1, NULL, 0, ikey,
+ hapd->conf->individual_wep_key_len,
+ KEY_FLAG_PAIRWISE_RX_TX)) {
+ wpa_printf(MSG_ERROR,
+ "Could not set individual WEP encryption");
}
os_free(ikey);
@@ -296,6 +298,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
const char *radius_mode_txt(struct hostapd_data *hapd)
@@ -347,13 +350,13 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
- if (identity == NULL)
+ if (!identity)
return;
/* Save station identity for future RADIUS packets */
os_free(sm->identity);
sm->identity = (u8 *) dup_binstr(identity, identity_len);
- if (sm->identity == NULL) {
+ if (!sm->identity) {
sm->identity_len = 0;
return;
}
@@ -408,7 +411,6 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
hapd->conf->group_mgmt_cipher);
@@ -421,7 +423,6 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
return -1;
}
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -608,8 +609,7 @@ int add_common_radius_attr(struct hostapd_data *hapd,
if (!radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
return -1;
}
}
@@ -682,18 +682,17 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
ieee802_1x_learn_identity(hapd, sm, eap, len);
- wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
- "packet");
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet");
sm->radius_identifier = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
- if (msg == NULL) {
+ if (!msg) {
wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -740,12 +739,12 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
+ wpa_printf(MSG_INFO,
+ "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
- if (res > 0) {
+ if (res > 0)
wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
- }
}
if (hapd->conf->radius_request_cui) {
@@ -774,8 +773,8 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
- "version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 AP version");
goto fail;
}
@@ -783,6 +782,7 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
const u8 *pos;
u8 buf[3];
u16 id;
+
pos = wpabuf_head_u8(sta->hs20_ie);
buf[0] = (*pos) >> 4;
if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
@@ -795,8 +795,8 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
msg,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
buf, sizeof(buf))) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
- "STA version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 STA version");
goto fail;
}
}
@@ -855,13 +855,14 @@ static void handle_eap_response(struct hostapd_data *hapd,
{
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -877,7 +878,7 @@ static void handle_eap_response(struct hostapd_data *hapd,
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
}
@@ -889,12 +890,11 @@ static void handle_eap_initiate(struct hostapd_data *hapd,
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO,
- "handle_eap_initiate: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -902,18 +902,41 @@ static void handle_eap_initiate(struct hostapd_data *hapd,
type = data[0];
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
- "id=%d len=%d) from STA: EAP Initiate type %u",
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u",
eap->code, eap->identifier, be_to_host16(eap->length),
type);
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
#endif /* CONFIG_ERP */
}
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_code_str(u8 code)
+{
+ switch (code) {
+ case EAP_CODE_REQUEST:
+ return "request";
+ case EAP_CODE_RESPONSE:
+ return "response";
+ case EAP_CODE_SUCCESS:
+ return "success";
+ case EAP_CODE_FAILURE:
+ return "failure";
+ case EAP_CODE_INITIATE:
+ return "initiate";
+ case EAP_CODE_FINISH:
+ return "finish";
+ default:
+ return "unknown";
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -929,44 +952,29 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
eap = (struct eap_hdr *) buf;
eap_len = be_to_host16(eap->length);
- wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
- eap->code, eap->identifier, eap_len);
+ wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d",
+ eap->code, eap_code_str(eap->code), eap->identifier,
+ eap_len);
if (eap_len < sizeof(*eap)) {
wpa_printf(MSG_DEBUG, " Invalid EAP length");
return;
} else if (eap_len > len) {
- wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP "
- "packet");
+ wpa_printf(MSG_DEBUG,
+ " Too short frame to contain this EAP packet");
return;
} else if (eap_len < len) {
- wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP "
- "packet", (unsigned long) len - eap_len);
+ wpa_printf(MSG_DEBUG,
+ " Ignoring %lu extra bytes after EAP packet",
+ (unsigned long) len - eap_len);
}
switch (eap->code) {
- case EAP_CODE_REQUEST:
- wpa_printf(MSG_DEBUG, " (request)");
- return;
case EAP_CODE_RESPONSE:
- wpa_printf(MSG_DEBUG, " (response)");
handle_eap_response(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_SUCCESS:
- wpa_printf(MSG_DEBUG, " (success)");
- return;
- case EAP_CODE_FAILURE:
- wpa_printf(MSG_DEBUG, " (failure)");
- return;
case EAP_CODE_INITIATE:
- wpa_printf(MSG_DEBUG, " (initiate)");
handle_eap_initiate(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_FINISH:
- wpa_printf(MSG_DEBUG, " (finish)");
- break;
- default:
- wpa_printf(MSG_DEBUG, " (unknown code)");
- return;
}
}
@@ -975,6 +983,7 @@ struct eapol_state_machine *
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
+
if (sta->flags & WLAN_STA_PREAUTH)
flags |= EAPOL_SM_PREAUTH;
if (sta->wpa_sm) {
@@ -1039,8 +1048,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
- "associated/Pre-authenticating STA");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X data frame from not associated/Pre-authenticating STA");
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
@@ -1062,14 +1071,15 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
+ wpa_printf(MSG_INFO,
+ " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
}
if (len - sizeof(*hdr) > datalen) {
- wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after "
- "IEEE 802.1X packet",
+ wpa_printf(MSG_DEBUG,
+ " ignoring %lu extra octets after IEEE 802.1X packet",
(unsigned long) len - sizeof(*hdr) - datalen);
}
@@ -1090,8 +1100,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "802.1X not enabled and WPS not used");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
return;
}
@@ -1099,8 +1109,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
if (key_mgmt != -1 &&
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
key_mgmt == WPA_KEY_MGMT_DPP)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "STA is using PSK");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - STA is using PSK");
return;
}
@@ -1123,15 +1133,14 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
* skipped if the STA is known to support WPS
* 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start "
- "EAPOL until EAPOL-Start is "
- "received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
}
/* since we support version 1, we can ignore version field and proceed
@@ -1148,18 +1157,17 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
case IEEE802_1X_TYPE_EAPOL_START:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Start from STA");
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
- HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
- "available - ignore it since "
- "STA sent EAPOL-Start");
+ HOSTAPD_LEVEL_DEBUG,
+ "cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
}
- sta->eapol_sm->eapolStart = TRUE;
+ sta->eapol_sm->eapolStart = true;
sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
@@ -1167,12 +1175,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
case IEEE802_1X_TYPE_EAPOL_LOGOFF:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Logoff from STA");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta);
- sta->eapol_sm->eapolLogoff = TRUE;
+ sta->eapol_sm->eapolLogoff = true;
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
break;
@@ -1180,8 +1188,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
case IEEE802_1X_TYPE_EAPOL_KEY:
wpa_printf(MSG_DEBUG, " EAPOL-Key");
if (!ap_sta_is_authorized(sta)) {
- wpa_printf(MSG_DEBUG, " Dropped key data from "
- "unauthorized Supplicant");
+ wpa_printf(MSG_DEBUG,
+ " Dropped key data from unauthorized Supplicant");
break;
}
break;
@@ -1237,8 +1245,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_WPS */
if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
- "802.1X not enabled or forced for WPS");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
@@ -1260,11 +1268,11 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
return;
}
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
@@ -1283,13 +1291,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* initiates the handshake with EAPOL-Start. Only allow the
* wait to be skipped if the STA is known to support WPS 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
- "EAPOL-Start is received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -1298,13 +1306,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from FT - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FT information from R0KH. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
ap_sta_bind_vlan(hapd, sta);
@@ -1321,13 +1329,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from FILS - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FILS information. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
@@ -1342,12 +1350,12 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing PMKSA information in the cache. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
@@ -1359,7 +1367,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* re-authentication without having to wait for the
* Supplicant to send EAPOL-Start.
*/
- sta->eapol_sm->reAuthenticate = TRUE;
+ sta->eapol_sm->reAuthenticate = true;
}
eapol_auth_step(sta->eapol_sm);
}
@@ -1380,7 +1388,7 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->pending_eapol_rx = NULL;
}
- if (sm == NULL)
+ if (!sm)
return;
sta->eapol_sm = NULL;
@@ -1405,32 +1413,32 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || sm->last_recv_radius == NULL) {
+ if (!sm || !sm->last_recv_radius) {
if (sm)
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
msg = sm->last_recv_radius;
eap = radius_msg_get_eap(msg);
- if (eap == NULL) {
+ if (!eap) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "could not extract "
- "EAP-Message from RADIUS message");
- sm->eap_if->aaaEapNoReq = TRUE;
+ HOSTAPD_LEVEL_WARNING,
+ "could not extract EAP-Message from RADIUS message");
+ sm->eap_if->aaaEapNoReq = true;
return;
}
if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "too short EAP packet "
- "received from authentication server");
+ HOSTAPD_LEVEL_WARNING,
+ "too short EAP packet received from authentication server");
wpabuf_free(eap);
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
@@ -1461,11 +1469,11 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
}
buf[sizeof(buf) - 1] = '\0';
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
- "id=%d len=%d) from RADIUS server: %s",
+ HOSTAPD_LEVEL_DEBUG,
+ "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf);
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
wpabuf_free(sm->eap_if->aaaEapReqData);
sm->eap_if->aaaEapReqData = eap;
@@ -1482,7 +1490,8 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
u8 *buf;
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
@@ -1503,7 +1512,7 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
keys->send, keys->send_len);
sm->eap_if->aaaEapKeyDataLen = len;
- sm->eap_if->aaaEapKeyAvailable = TRUE;
+ sm->eap_if->aaaEapKeyAvailable = true;
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1545,8 +1554,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
struct radius_attr_data *nclass;
size_t nclass_count;
- if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
- sm == NULL)
+ if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
return;
radius_free_class(&sm->radius_class);
@@ -1555,7 +1563,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
return;
nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (nclass == NULL)
+ if (!nclass)
return;
nclass_count = 0;
@@ -1572,7 +1580,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
} while (class_len < 1);
nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (nclass[nclass_count].data == NULL)
+ if (!nclass[nclass_count].data)
break;
nclass[nclass_count].len = class_len;
@@ -1581,8 +1589,9 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
sm->radius_class.attr = nclass;
sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
- "attributes for " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
(unsigned long) sm->radius_class.count,
MAC2STR(sta->addr));
}
@@ -1597,7 +1606,7 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
@@ -1605,12 +1614,12 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
return;
identity = (u8 *) dup_binstr(buf, len);
- if (identity == NULL)
+ if (!identity)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
- "User-Name from Access-Accept '%s'",
+ HOSTAPD_LEVEL_DEBUG,
+ "old identity '%s' updated with User-Name from Access-Accept '%s'",
sm->identity ? (char *) sm->identity : "N/A",
(char *) identity);
@@ -1630,7 +1639,7 @@ static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
u8 *buf;
size_t len;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -1638,7 +1647,7 @@ static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
return;
cui = wpabuf_alloc_copy(buf, len);
- if (cui == NULL)
+ if (!cui)
return;
wpabuf_free(sm->radius_cui);
@@ -1659,14 +1668,16 @@ static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
sta->remediation_method = pos[0];
os_memcpy(sta->remediation_url, pos + 1, len - 1);
sta->remediation_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR " - server method %u URL %s",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR " - server method %u URL %s",
MAC2STR(sta->addr), sta->remediation_method,
sta->remediation_url);
} else {
sta->remediation_url = NULL;
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR, MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR, MAC2STR(sta->addr));
}
/* TODO: assign the STA into remediation VLAN or add filtering */
}
@@ -1679,8 +1690,8 @@ static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
if (len < 3)
return; /* Malformed information */
sta->hs20_deauth_requested = 1;
- wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
- "Re-auth Delay %u",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
*pos, WPA_GET_LE16(pos + 1));
wpabuf_free(sta->hs20_deauth_req);
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
@@ -1704,16 +1715,17 @@ static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
return; /* Malformed information */
os_free(sta->hs20_session_info_url);
sta->hs20_session_info_url = os_malloc(len);
- if (sta->hs20_session_info_url == NULL)
+ if (!sta->hs20_session_info_url)
return;
swt = pos[0];
os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
sta->hs20_session_info_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
- "(session_timeout=%d)",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)",
sta->hs20_session_info_url, swt, session_timeout);
if (session_timeout < 0) {
- wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: No Session-Timeout set - ignore session info URL");
return;
}
if (swt == 255)
@@ -1846,6 +1858,7 @@ static struct eapol_state_machine *
ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
{
struct sta_id_search id_search;
+
id_search.identifier = identifier;
id_search.sm = NULL;
ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
@@ -1867,7 +1880,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
if (vlan_desc.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- sta->eapol_sm->authFail = TRUE;
+ sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
@@ -1880,7 +1893,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!vlan_desc.notempty) {
- sta->eapol_sm->authFail = TRUE;
+ sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
"authentication server did not include required VLAN ID in Access-Accept");
@@ -1916,9 +1929,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
- if (sm == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
- "station for this RADIUS message");
+ if (!sm) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Could not find matching station for this RADIUS message");
return RADIUS_RX_UNKNOWN;
}
sta = sm->sta;
@@ -1929,12 +1942,12 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
0) < 0 &&
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
- "Message-Authenticator since it does not include "
- "EAP-Message");
+ wpa_printf(MSG_DEBUG,
+ "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -1967,8 +1980,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
- "ignored too small "
- "Acct-Interim-Interval %d",
+ "ignored too small Acct-Interim-Interval %d",
acct_interim_interval);
} else
sta->acct_interim_interval = acct_interim_interval;
@@ -2007,7 +2019,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
else
ap_sta_no_session_timeout(hapd, sta);
- sm->eap_if->aaaSuccess = TRUE;
+ sm->eap_if->aaaSuccess = true;
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
@@ -2019,7 +2031,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
(int) session_timeout : -1);
break;
case RADIUS_CODE_ACCESS_REJECT:
- sm->eap_if->aaaFail = TRUE;
+ sm->eap_if->aaaFail = true;
override_eapReq = 1;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
&reason_code) == 0) {
@@ -2030,15 +2042,14 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
if (session_timeout_set) {
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
sm->eap_if->aaaMethodTimeout = session_timeout;
hostapd_logger(hapd, sm->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
- "using EAP timeout of %d seconds (from "
- "RADIUS)",
+ "using EAP timeout of %d seconds (from RADIUS)",
sm->eap_if->aaaMethodTimeout);
} else {
/*
@@ -2052,11 +2063,12 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_decapsulate_radius(hapd, sta);
if (override_eapReq)
- sm->eap_if->aaaEapReq = FALSE;
+ sm->eap_if->aaaEapReq = false;
#ifdef CONFIG_FILS
#ifdef NEED_AP_MLME
- if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+ if (sta->flags &
+ (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) {
/* TODO: Add a PMKSA entry on success? */
ieee802_11_finish_fils_auth(
hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
@@ -2077,7 +2089,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -2097,13 +2110,15 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
MAC2STR(sta->addr));
- sm->eap_if->portEnabled = FALSE;
+ sm->eap_if->portEnabled = false;
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
}
+#ifdef CONFIG_WEP
+
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -2113,7 +2128,7 @@ static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
os_free(eapol->default_wep_key);
eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
- if (eapol->default_wep_key == NULL ||
+ if (!eapol->default_wep_key ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
wpa_printf(MSG_INFO, "Could not generate random WEP key");
@@ -2134,7 +2149,7 @@ static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx)
{
if (sta->eapol_sm) {
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
eapol_auth_step(sta->eapol_sm);
}
return 0;
@@ -2157,8 +2172,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to generate a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to generate a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2168,12 +2183,13 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
* after new broadcast key has been sent to all stations. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
broadcast_ether_addr,
- eapol->default_wep_key_idx, 1, NULL, 0,
+ eapol->default_wep_key_idx, 0, 1, NULL, 0,
eapol->default_wep_key,
- hapd->conf->default_wep_key_len)) {
+ hapd->conf->default_wep_key_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to configure a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to configure a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2187,6 +2203,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
}
}
+#endif /* CONFIG_WEP */
+
static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
const u8 *data, size_t datalen)
@@ -2208,8 +2226,8 @@ static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
(identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR,
WSC_ID_REGISTRAR_LEN) == 0))) {
- wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
- "WLAN_STA_WPS");
+ wpa_printf(MSG_DEBUG,
+ "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS");
sta->flags |= WLAN_STA_WPS;
}
}
@@ -2236,6 +2254,7 @@ static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
@@ -2253,7 +2272,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
- if (eap_user == NULL)
+ if (!eap_user)
goto out;
os_memset(user, 0, sizeof(*user));
@@ -2266,7 +2285,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
if (eap_user->password) {
user->password = os_memdup(eap_user->password,
eap_user->password_len);
- if (user->password == NULL)
+ if (!user->password)
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
@@ -2296,8 +2315,9 @@ static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+
sta = ap_get_sta(hapd, addr);
- if (sta == NULL || sta->eapol_sm == NULL)
+ if (!sta || !sta->eapol_sm)
return 0;
return 1;
}
@@ -2334,6 +2354,7 @@ static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_set_sta_authorized(hapd, sta, authorized);
}
@@ -2342,20 +2363,24 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_abort_auth(hapd, sta);
}
+#ifdef CONFIG_WEP
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 */
}
+#endif /* CONFIG_WEP */
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
@@ -2363,6 +2388,7 @@ static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
{
/* struct hostapd_data *hapd = ctx; */
struct sta_info *sta = sta_ctx;
+
switch (type) {
case EAPOL_AUTH_SM_CHANGE:
wpa_auth_sm_notify(sta->wpa_sm);
@@ -2405,51 +2431,23 @@ static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
int ieee802_1x_init(struct hostapd_data *hapd)
{
- int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
dl_list_init(&hapd->erp_keys);
os_memset(&conf, 0, sizeof(conf));
+ conf.eap_cfg = hapd->eap_cfg;
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
+#ifdef CONFIG_WEP
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
- conf.eap_server = hapd->conf->eap_server;
- conf.ssl_ctx = hapd->ssl_ctx;
- conf.msg_ctx = hapd->msg_ctx;
- conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+#endif /* CONFIG_WEP */
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
- conf.erp = hapd->conf->eap_server_erp;
- conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
- conf.tls_flags = hapd->conf->tls_flags;
- 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;
- conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
- conf.eap_fast_prov = hapd->conf->eap_fast_prov;
- conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
- conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
- conf.eap_teap_auth = hapd->conf->eap_teap_auth;
- conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
- conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
- conf.eap_sim_id = hapd->conf->eap_sim_id;
- conf.tnc = hapd->conf->tnc;
- conf.wps = hapd->wps;
- conf.fragment_size = hapd->conf->fragment_size;
- conf.pwd_group = hapd->conf->pwd_group;
- conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
- if (hapd->conf->server_id) {
- conf.server_id = (const u8 *) hapd->conf->server_id;
- conf.server_id_len = os_strlen(hapd->conf->server_id);
- } else {
- conf.server_id = (const u8 *) "hostapd";
- conf.server_id_len = 7;
- }
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -2460,7 +2458,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
cb.logger = ieee802_1x_logger;
cb.set_port_authorized = ieee802_1x_set_port_authorized;
cb.abort_auth = _ieee802_1x_abort_auth;
+#ifdef CONFIG_WEP
cb.tx_key = _ieee802_1x_tx_key;
+#endif /* CONFIG_WEP */
cb.eapol_event = ieee802_1x_eapol_event;
#ifdef CONFIG_ERP
cb.erp_get_key = ieee802_1x_erp_get_key;
@@ -2468,7 +2468,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
- if (hapd->eapol_auth == NULL)
+ if (!hapd->eapol_auth)
return -1;
if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
@@ -2481,17 +2481,21 @@ int ieee802_1x_init(struct hostapd_data *hapd)
return -1;
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_WEP
if (hapd->conf->default_wep_key_len) {
+ int i;
+
for (i = 0; i < 4; i++)
hostapd_drv_set_key(hapd->conf->iface, hapd,
- WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ WPA_ALG_NONE, NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP);
ieee802_1x_rekey(hapd, NULL);
- if (hapd->eapol_auth->default_wep_key == NULL)
+ if (!hapd->eapol_auth->default_wep_key)
return -1;
}
+#endif /* CONFIG_WEP */
return 0;
}
@@ -2511,7 +2515,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
+#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+#endif /* CONFIG_WEP */
if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
@@ -2532,7 +2538,7 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
- if (sta == NULL)
+ if (!sta)
return -1;
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
@@ -2561,8 +2567,8 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
if (len < (int) sizeof(*xhdr))
return 0;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
- "type=%d length=%d - ack=%d",
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " TX status - version=%d type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
@@ -2581,6 +2587,7 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
+
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
wpa->type == EAPOL_KEY_TYPE_WPA)
@@ -2596,8 +2603,8 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
- "frame (%scast index=%d)",
+ HOSTAPD_LEVEL_DEBUG,
+ "did not Ack EAPOL-Key frame (%scast index=%d)",
key->key_index & BIT(7) ? "uni" : "broad",
key->key_index & ~BIT(7));
/* TODO: re-send EAPOL-Key couple of times (with short delay
@@ -2617,7 +2624,7 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
{
- if (sm == NULL || sm->identity == NULL)
+ if (!sm || !sm->identity)
return NULL;
*len = sm->identity_len;
@@ -2628,7 +2635,7 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx)
{
- if (sm == NULL || sm->radius_class.attr == NULL ||
+ if (!sm || !sm->radius_class.attr ||
idx >= (int) sm->radius_class.count)
return NULL;
@@ -2639,7 +2646,7 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return NULL;
return sm->radius_cui;
}
@@ -2648,7 +2655,7 @@ struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
- if (sm == NULL)
+ if (!sm)
return NULL;
*len = sm->eap_if->eapKeyDataLen;
@@ -2671,28 +2678,27 @@ const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
- int enabled)
+ bool enabled)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+ sm->eap_if->portEnabled = enabled;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
- int valid)
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->portValid = valid ? TRUE : FALSE;
+ sm->portValid = valid;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth)
{
- if (sm == NULL)
+ if (!sm)
return;
if (pre_auth)
sm->flags |= EAPOL_SM_PREAUTH;
@@ -2701,7 +2707,7 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
}
-static const char * bool_txt(Boolean val)
+static const char * bool_txt(bool val)
{
return val ? "TRUE" : "FALSE";
}
@@ -2724,7 +2730,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
const char *name2;
char *identity_buf = NULL;
- if (sm == NULL)
+ if (!sm)
return 0;
ret = os_snprintf(buf + len, buflen - len,
diff --git a/contrib/wpa/src/ap/ieee802_1x.h b/contrib/wpa/src/ap/ieee802_1x.h
index bb85b93d69a5..70dc11afec74 100644
--- a/contrib/wpa/src/ap/ieee802_1x.h
+++ b/contrib/wpa/src/ap/ieee802_1x.h
@@ -42,10 +42,9 @@ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
- int enabled);
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
- int valid);
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
+ bool enabled);
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
diff --git a/contrib/wpa/src/ap/neighbor_db.c b/contrib/wpa/src/ap/neighbor_db.c
index 54154432286b..2bbe31859214 100644
--- a/contrib/wpa/src/ap/neighbor_db.c
+++ b/contrib/wpa/src/ap/neighbor_db.c
@@ -34,6 +34,60 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
}
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+ struct hostapd_neighbor_entry *nr;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int ret;
+ char nrie[2 * 255 + 1];
+ char lci[2 * 255 + 1];
+ char civic[2 * 255 + 1];
+ char ssid[SSID_MAX_LEN * 2 + 1];
+
+ ssid[0] = '\0';
+ wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
+ nr->ssid.ssid_len);
+
+ nrie[0] = '\0';
+ if (nr->nr)
+ wpa_snprintf_hex(nrie, sizeof(nrie),
+ wpabuf_head(nr->nr),
+ wpabuf_len(nr->nr));
+
+ lci[0] = '\0';
+ if (nr->lci)
+ wpa_snprintf_hex(lci, sizeof(lci),
+ wpabuf_head(nr->lci),
+ wpabuf_len(nr->lci));
+
+ civic[0] = '\0';
+ if (nr->civic)
+ wpa_snprintf_hex(civic, sizeof(civic),
+ wpabuf_head(nr->civic),
+ wpabuf_len(nr->civic));
+
+ ret = os_snprintf(pos, end - pos, MACSTR
+ " ssid=%s%s%s%s%s%s%s%s\n",
+ MAC2STR(nr->bssid), ssid,
+ nr->nr ? " nr=" : "", nrie,
+ nr->lci ? " lci=" : "", lci,
+ nr->civic ? " civic=" : "", civic,
+ nr->stationary ? " stat" : "");
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
{
wpabuf_free(nr->nr);
@@ -166,7 +220,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
- int he = hapd->iconf->ieee80211ax;
+ int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -202,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
}
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
diff --git a/contrib/wpa/src/ap/neighbor_db.h b/contrib/wpa/src/ap/neighbor_db.h
index 9c8f4f2dd69d..bed0a2f5fb7f 100644
--- a/contrib/wpa/src/ap/neighbor_db.h
+++ b/contrib/wpa/src/ap/neighbor_db.h
@@ -13,6 +13,7 @@
struct hostapd_neighbor_entry *
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.c b/contrib/wpa/src/ap/pmksa_cache_auth.c
index 15e2c4943f2b..b67b8522e744 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.c
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.c
@@ -516,6 +516,12 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
+ if (wpa_key_mgmt_sae(entry->akmp) ||
+ wpa_key_mgmt_fils(entry->akmp)) {
+ if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ continue;
+ }
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
diff --git a/contrib/wpa/src/ap/preauth_auth.c b/contrib/wpa/src/ap/preauth_auth.c
index 3e0c8000d062..2ff1861772f7 100644
--- a/contrib/wpa/src/ap/preauth_auth.c
+++ b/contrib/wpa/src/ap/preauth_auth.c
@@ -82,7 +82,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->portValid = true;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}
diff --git a/contrib/wpa/src/ap/sta_info.c b/contrib/wpa/src/ap/sta_info.c
index 51d788436548..ccd1ed931bad 100644
--- a/contrib/wpa/src/ap/sta_info.c
+++ b/contrib/wpa/src/ap/sta_info.c
@@ -46,9 +46,7 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
-#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
@@ -158,6 +156,37 @@ void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
}
+#ifdef CONFIG_PASN
+
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
+ MAC2STR(sta->addr));
+
+ if (sta->pasn->ecdh)
+ crypto_ecdh_deinit(sta->pasn->ecdh);
+
+ wpabuf_free(sta->pasn->secret);
+ sta->pasn->secret = NULL;
+
+#ifdef CONFIG_SAE
+ sae_clear_data(&sta->pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ /* In practice this pointer should be NULL */
+ wpabuf_free(sta->pasn->fils.erp_resp);
+ sta->pasn->fils.erp_resp = NULL;
+#endif /* CONFIG_FILS */
+
+ bin_clear_free(sta->pasn, sizeof(*sta->pasn));
+ sta->pasn = NULL;
+ }
+}
+
+#endif /* CONFIG_PASN */
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -166,6 +195,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -235,9 +265,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
sta->assoc_ie_taxonomy = NULL;
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
@@ -248,10 +276,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_P2P */
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+#ifdef NEED_AP_MLME
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME */
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
@@ -301,10 +329,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->challenge);
-#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
@@ -331,6 +357,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->vht_capabilities);
os_free(sta->vht_operation);
os_free(sta->he_capab);
+ os_free(sta->he_6ghz_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -375,8 +402,16 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
#endif /* CONFIG_WNM_AP */
+#ifdef CONFIG_PASN
+ ap_free_sta_pasn(hapd, sta);
+#endif /* CONFIG_PASN */
+
os_free(sta->ifname_wds);
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(sta->sae_postponed_commit);
+#endif /* CONFIG_TESTING_OPTIONS */
+
os_free(sta);
}
@@ -546,6 +581,7 @@ skip_poll:
case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
+ hostapd_set_sta_flags(hapd, sta);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
@@ -590,7 +626,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED))) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
@@ -813,6 +850,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
sta->timeout_next = STA_DEAUTH;
}
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -863,6 +901,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
@@ -1028,6 +1067,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
int ret;
int old_vlanid = sta->vlan_id_bound;
+ if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Do not override WDS VLAN assignment for STA "
+ MACSTR, MAC2STR(sta->addr));
+ return 0;
+ }
+
iface = hapd->conf->iface;
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
@@ -1049,7 +1095,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->vlan_id == old_vlanid)
goto skip_counting;
- if (sta->vlan_id > 0 && vlan == NULL) {
+ if (sta->vlan_id > 0 && !vlan &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
@@ -1095,8 +1142,6 @@ done:
}
-#ifdef CONFIG_IEEE80211W
-
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
@@ -1135,6 +1180,8 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
+ if (sta->sa_query_count >= 1000)
+ return;
nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1,
@@ -1186,8 +1233,6 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
sta->sa_query_count = 0;
}
-#endif /* CONFIG_IEEE80211W */
-
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -1324,9 +1369,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
if (sta == NULL)
return;
ap_sta_set_authorized(hapd, sta, 0);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
@@ -1414,7 +1460,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen,
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1433,6 +1480,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_HE ? "[HE]" : ""),
+ (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
@@ -1486,3 +1535,33 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta);
}
+
+
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ /*
+ * If a station that is already associated to the AP, is trying to
+ * authenticate again, remove the STA entry, in order to make sure the
+ * STA PS state gets cleared and configuration gets updated. To handle
+ * this, station's added_unassoc flag is cleared once the station has
+ * completed association.
+ */
+ ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+ sta->supported_rates,
+ sta->supported_rates_len,
+ 0, NULL, NULL, NULL, 0, NULL,
+ sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ return -1;
+ }
+
+ sta->added_unassoc = 1;
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/sta_info.h b/contrib/wpa/src/ap/sta_info.h
index 5456a63a7c26..27e72f9a0164 100644
--- a/contrib/wpa/src/ap/sta_info.h
+++ b/contrib/wpa/src/ap/sta_info.h
@@ -14,6 +14,8 @@
#include "vlan.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
+#include "crypto/sha384.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -38,6 +40,8 @@
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24)
+#define WLAN_STA_6GHZ BIT(25)
+#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -62,6 +66,43 @@ struct pending_eapol_rx {
struct os_reltime rx_time;
};
+enum pasn_fils_state {
+ PASN_FILS_STATE_NONE = 0,
+ PASN_FILS_STATE_PENDING_AS,
+ PASN_FILS_STATE_COMPLETE
+};
+
+struct pasn_fils_data {
+ u8 state;
+ u8 nonce[FILS_NONCE_LEN];
+ u8 anonce[FILS_NONCE_LEN];
+ u8 session[FILS_SESSION_LEN];
+ u8 erp_pmkid[PMKID_LEN];
+
+ struct wpabuf *erp_resp;
+};
+
+struct pasn_data {
+ int akmp;
+ int cipher;
+ u16 group;
+ u8 trans_seq;
+ u8 wrapped_data_format;
+ size_t kdk_len;
+
+ u8 hash[SHA384_MAC_LEN];
+ struct wpa_ptk ptk;
+ struct crypto_ecdh *ecdh;
+
+ struct wpabuf *secret;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ struct pasn_fils_data fils;
+#endif /* CONFIG_FILS */
+};
+
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@@ -121,6 +162,7 @@ struct sta_info {
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1;
+ unsigned int post_csa_sa_query:1;
u16 auth_alg;
@@ -170,8 +212,8 @@ struct sta_info {
u8 vht_opmode;
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
+ struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
-#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
@@ -179,7 +221,6 @@ struct sta_info {
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_reltime sa_query_start;
-#endif /* CONFIG_IEEE80211W */
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
@@ -278,11 +319,17 @@ struct sta_info {
int last_tk_key_idx;
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
+ u8 *sae_postponed_commit;
+ size_t sae_postponed_commit_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_PASN
+ struct pasn_data *pasn;
+#endif /* CONFIG_PASN */
};
@@ -358,5 +405,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
+
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/contrib/wpa/src/ap/utils.c b/contrib/wpa/src/ap/utils.c
index fcb371bec283..bedad6eb02f7 100644
--- a/contrib/wpa/src/ap/utils.c
+++ b/contrib/wpa/src/ap/utils.c
@@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (ohapd->conf->skip_prune_assoc)
+ continue;
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */
if (ohapd->iface->fst &&
diff --git a/contrib/wpa/src/ap/vlan_init.c b/contrib/wpa/src/ap/vlan_init.c
index e293a003303f..53eacfb458c8 100644
--- a/contrib/wpa/src/ap/vlan_init.c
+++ b/contrib/wpa/src/ap/vlan_init.c
@@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
- int ret, i;
+ int ret;
+#ifdef CONFIG_WEP
+ int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[i])
@@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
vlan->ifname);
return -1;
}
+#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
diff --git a/contrib/wpa/src/ap/wmm.c b/contrib/wpa/src/ap/wmm.c
index dc734933738d..9ebb01e3d748 100644
--- a/contrib/wpa/src/ap/wmm.c
+++ b/contrib/wpa/src/ap/wmm.c
@@ -111,9 +111,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
- struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
+ struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
int e;
+ os_memset(wmmp, 0, sizeof(wmmp));
+
if (!hapd->conf->wmm_enabled)
return eid;
wmm_calc_regulatory_limit(hapd, wmmp);
@@ -209,7 +211,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
- if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
@@ -291,10 +293,11 @@ int wmm_process_tspec(struct wmm_tspec_element *tspec)
static void wmm_addts_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
- struct wmm_tspec_element *tspec, size_t len)
+ const struct wmm_tspec_element *tspec, size_t len)
{
const u8 *end = ((const u8 *) mgmt) + len;
int res;
+ struct wmm_tspec_element tspec_resp;
if ((const u8 *) (tspec + 1) > end) {
wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
@@ -306,10 +309,11 @@ static void wmm_addts_req(struct hostapd_data *hapd,
mgmt->u.action.u.wmm_action.dialog_token,
MAC2STR(mgmt->sa));
- res = wmm_process_tspec(tspec);
+ os_memcpy(&tspec_resp, tspec, sizeof(struct wmm_tspec_element));
+ res = wmm_process_tspec(&tspec_resp);
wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
- wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+ wmm_send_action(hapd, mgmt->sa, &tspec_resp, WMM_ACTION_CODE_ADDTS_RESP,
mgmt->u.action.u.wmm_action.dialog_token, res);
}
diff --git a/contrib/wpa/src/ap/wnm_ap.c b/contrib/wpa/src/ap/wnm_ap.c
index 27c69d34a7ca..d32967e6cef6 100644
--- a/contrib/wpa/src/ap/wnm_ap.c
+++ b/contrib/wpa/src/ap/wnm_ap.c
@@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
+ size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len;
@@ -102,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_wnm_sleep);
+ ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -122,8 +132,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ MAX_BIGTK_SUBELEM_LEN +
oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -150,7 +162,6 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
-#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -158,11 +169,21 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
-#endif /* CONFIG_IEEE80211W */
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION)) {
+ res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+ if (res < 0)
+ goto fail;
+ bigtk_elem_len = res;
+ pos += bigtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+ (int) bigtk_elem_len);
+ }
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
- gtk_elem_len + igtk_elem_len);
+ gtk_elem_len + igtk_elem_len + bigtk_elem_len);
}
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
@@ -178,7 +199,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
+ igtk_elem_len + bigtk_elem_len +
+ wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -191,8 +213,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
/* when entering wnmsleep
* 1. pause the node in driver
- * 2. mark the node so that AP won't update GTK/IGTK during
- * WNM Sleep
+ * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+ * during WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -203,7 +225,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
}
/* when exiting wnmsleep
* 1. unmark the node
- * 2. start GTK/IGTK update if MFP is not used
+ * 2. start GTK/IGTK/BIGTK update if MFP is not used
* 3. unpause the node in driver
*/
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -223,6 +245,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
os_free(oci_ie);
@@ -305,8 +328,9 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
@@ -510,6 +534,31 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
}
+static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct sta_info *sta;
+
+ if (!hapd->conf->beacon_prot ||
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received WNM-Notification Request",
+ MAC2STR(addr));
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Beacon protection failure reported");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
+ MACSTR, MAC2STR(addr));
+}
+
+
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf,
size_t len)
@@ -528,8 +577,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
MAC2STR(addr), dialog_token, type);
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
buf, len);
- if (type == WLAN_EID_VENDOR_SPECIFIC)
+ switch (type) {
+ case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
+ wnm_beacon_protection_failure(hapd, addr);
+ break;
+ case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+ break;
+ }
}
@@ -643,7 +698,7 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -716,7 +771,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
os_memcpy(pos, url, url_len);
pos += url_len;
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -792,7 +847,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
mbo_len);
}
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
@@ -836,7 +891,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;
diff --git a/contrib/wpa/src/ap/wpa_auth.c b/contrib/wpa/src/ap/wpa_auth.c
index c56077001efa..83805681ed97 100644
--- a/contrib/wpa/src/ap/wpa_auth.c
+++ b/contrib/wpa/src/ap/wpa_auth.c
@@ -14,6 +14,8 @@
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@@ -56,13 +58,14 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, int force_sha256);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -105,7 +108,7 @@ static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb->get_eapol == NULL)
+ if (!wpa_auth->cb->get_eapol)
return -1;
return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
@@ -117,7 +120,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *prev_psk, size_t *psk_len,
int *vlan_id)
{
- if (wpa_auth->cb->get_psk == NULL)
+ if (!wpa_auth->cb->get_psk)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
prev_psk, psk_len, vlan_id);
@@ -127,7 +130,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb->get_msk == NULL)
+ if (!wpa_auth->cb->get_msk)
return -1;
return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -136,21 +139,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
- if (wpa_auth->cb->set_key == NULL)
+ if (!wpa_auth->cb->set_key)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb->get_seqnum == NULL)
+ int res;
+
+ if (!wpa_auth->cb->get_seqnum)
return -1;
- return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+ res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override GTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+ if (!addr && idx >= 4 && idx <= 5 &&
+ wpa_auth->conf.igtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override IGTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return res;
}
@@ -158,7 +186,7 @@ static inline int
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb->send_eapol == NULL)
+ if (!wpa_auth->cb->send_eapol)
return -1;
return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
encrypt);
@@ -169,7 +197,7 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb->start_ampe == NULL)
+ if (!wpa_auth->cb->start_ampe)
return -1;
return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
@@ -180,7 +208,7 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_sta == NULL)
+ if (!wpa_auth->cb->for_each_sta)
return 0;
return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -190,16 +218,33 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_auth == NULL)
+ if (!wpa_auth->cb->for_each_auth)
return 0;
return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
+void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ if (wpa_auth->cb->store_ptksa)
+ wpa_auth->cb->store_ptksa(wpa_auth->cb_ctx, addr, cipher,
+ life_time, ptk);
+}
+
+
+void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher)
+{
+ if (wpa_auth->cb->clear_ptksa)
+ wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
+}
+
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -212,7 +257,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
int maxlen;
va_list ap;
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
maxlen = os_strlen(fmt) + 100;
@@ -233,7 +278,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
const u8 *addr, u16 reason)
{
- if (wpa_auth->cb->disconnect == NULL)
+ if (!wpa_auth->cb->disconnect)
return;
wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
MAC2STR(addr), reason);
@@ -266,8 +311,8 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
struct wpa_authenticator *wpa_auth = eloop_ctx;
if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
} else {
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
wpa_hexdump_key(MSG_DEBUG, "GMK",
@@ -291,9 +336,9 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
while (group) {
wpa_group_get(wpa_auth, group);
- group->GTKReKey = TRUE;
+ group->GTKReKey = true;
do {
- group->changed = FALSE;
+ group->changed = false;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
@@ -391,17 +436,16 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group;
group = os_zalloc(sizeof(struct wpa_group));
- if (group == NULL)
+ if (!group)
return NULL;
- group->GTKAuthenticator = TRUE;
+ group->GTKAuthenticator = true;
group->vlan_id = vlan_id;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "for secure operations - update keys later when "
- "the first station connects");
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
}
/*
@@ -411,20 +455,20 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
* on embedded devices.
*/
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
os_free(group);
return NULL;
}
- group->GInit = TRUE;
+ group->GInit = true;
if (delay_init) {
- wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
- "until Beacon frames have been configured");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Delay group state machine start until Beacon frames have been configured");
/* Initialization is completed in wpa_init_keys(). */
} else {
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
}
@@ -447,7 +491,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_authenticator *wpa_auth;
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -461,7 +505,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
}
wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
- if (wpa_auth->group == NULL) {
+ if (!wpa_auth->group) {
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -469,7 +513,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
wpa_auth);
- if (wpa_auth->pmksa == NULL) {
+ if (!wpa_auth->pmksa) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -479,7 +523,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
- if (wpa_auth->ft_pmk_cache == NULL) {
+ if (!wpa_auth->ft_pmk_cache) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -518,10 +562,10 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth)
{
struct wpa_group *group = wpa_auth->group;
- wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
- "keys");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Start group state machine to set initial keys");
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
@@ -575,7 +619,8 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+
+ if (!wpa_auth)
return 0;
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -590,9 +635,9 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
*/
group = wpa_auth->group;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
- group->GInit = TRUE;
+ group->GInit = true;
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
return 0;
@@ -609,7 +654,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
return NULL;
sm = os_zalloc(sizeof(struct wpa_state_machine));
- if (sm == NULL)
+ if (!sm)
return NULL;
os_memcpy(sm->addr, addr, ETH_ALEN);
if (p2p_dev_addr)
@@ -626,17 +671,16 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm)
{
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return -1;
#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "FT authentication already completed - do not "
- "start 4-way handshake");
+ "FT authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -647,14 +691,14 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
"FILS authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_FILS */
if (sm->started) {
os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -662,11 +706,11 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
"start authentication");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -676,7 +720,7 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
/* WPA/RSN was not used - clear WPA state. This is needed if the STA
* reassociates back to the same AP while the previous entry for the
* STA has not yet been removed. */
- if (sm == NULL)
+ if (!sm)
return;
sm->wpa_key_mgmt = 0;
@@ -688,8 +732,9 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
u32 start;
- wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
- "address %u.%u.%u.%u from " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free assigned IP address %u.%u.%u.%u from "
+ MACSTR,
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
MAC2STR(sm->addr));
@@ -700,7 +745,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
}
#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
@@ -708,6 +753,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
+ os_free(sm->rsnxe);
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -718,31 +764,34 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ struct wpa_authenticator *wpa_auth;
+
+ if (!sm)
return;
- if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "strict rekeying - force GTK rekey since STA "
- "is leaving");
+ wpa_auth = sm->wpa_auth;
+ if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "strict rekeying - force GTK rekey since STA is leaving");
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- sm->wpa_auth, NULL) == -1)
- eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
- NULL);
+ wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk,
+ wpa_auth, NULL);
}
- eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_sta_deinit(sm);
#endif /* CONFIG_IEEE80211R_AP */
if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */
- wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Registering pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
sm->pending_deinit = 1;
} else
wpa_free_sta_sm(sm);
@@ -751,11 +800,23 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
static void wpa_request_new_ptk(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->PTKRequest = TRUE;
- sm->PTK_valid = 0;
+ if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+ MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ } else {
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+ sm->PTKRequest = true;
+ sm->PTK_valid = 0;
+ }
}
@@ -780,10 +841,10 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
int i;
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (ctr[i].valid &&
- (replay_counter == NULL ||
+ (!replay_counter ||
os_memcmp(replay_counter, ctr[i].counter,
WPA_REPLAY_COUNTER_LEN) == 0))
- ctr[i].valid = FALSE;
+ ctr[i].valid = false;
}
}
@@ -797,9 +858,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct rsn_mdie *mdie;
if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
- ie.num_pmkid != 1 || ie.pmkid == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
- "FT 4-way handshake message 2/4");
+ ie.num_pmkid != 1 || !ie.pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKR1Name in FT 4-way handshake message 2/4");
return -1;
}
@@ -808,8 +869,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
sm->sup_pmk_r1_name, PMKID_LEN);
if (!kde->mdie || !kde->ftie) {
- wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
- "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+ wpa_printf(MSG_DEBUG,
+ "FT: No %s in FT 4-way handshake message 2/4",
+ kde->mdie ? "FTIE" : "MDIE");
return -1;
}
@@ -843,18 +905,15 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Error Request "
- "(STA detected Michael MIC failure (group=%d))",
+ "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
group);
if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "group cipher is not TKIP");
+ "ignore Michael MIC failure report since group cipher is not TKIP");
} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "pairwise cipher is not TKIP");
+ "ignore Michael MIC failure report since pairwise cipher is not TKIP");
} else {
if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
return 1; /* STA entry was removed */
@@ -887,7 +946,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -900,7 +959,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+ 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -935,12 +995,24 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
- sm->PTK_valid = TRUE;
+ sm->PTK_valid = true;
return 0;
}
+static bool wpa_auth_gtk_rekey_in_process(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group;
+
+ for (group = wpa_auth->group; group; group = group->next) {
+ if (group->GKeyDoneStations)
+ return true;
+ }
+ return false;
+}
+
+
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len)
@@ -955,7 +1027,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
size_t keyhdrlen, mic_len;
u8 *mic;
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return;
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
@@ -974,20 +1046,19 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key_data = mic + mic_len + 2;
key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type,
- (unsigned int) mic_len, key_data_length);
+ mic_len, key_data_length);
wpa_hexdump(MSG_MSGDUMP,
"WPA: EAPOL-Key header (ending before Key MIC)",
key, sizeof(*key));
wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
- wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %lu)",
+ wpa_printf(MSG_INFO,
+ "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
key_data_length,
- (unsigned long) (data_len - sizeof(*hdr) -
- keyhdrlen));
+ data_len - sizeof(*hdr) - keyhdrlen);
return;
}
@@ -997,18 +1068,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* Some deployed station implementations seem to send
* msg 4/4 with incorrect type value in WPA2 mode.
*/
- wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
- "with unexpected WPA type in RSN mode");
+ wpa_printf(MSG_DEBUG,
+ "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
} else if (key->type != EAPOL_KEY_TYPE_RSN) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in RSN mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in RSN mode",
key->type);
return;
}
} else {
if (key->type != EAPOL_KEY_TYPE_WPA) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in WPA mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in WPA mode",
key->type);
return;
}
@@ -1053,9 +1124,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "advertised support for "
- "AES-128-CMAC, but did not "
- "use it");
+ "advertised support for AES-128-CMAC, but did not use it");
return;
}
@@ -1064,8 +1133,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "did not use HMAC-SHA1-AES "
- "with CCMP/GCMP");
+ "did not use HMAC-SHA1-AES with CCMP/GCMP");
return;
}
}
@@ -1083,8 +1151,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
os_memcmp(key->replay_counter, sm->req_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
- "received EAPOL-Key request with "
- "replayed counter");
+ "received EAPOL-Key request with replayed counter");
return;
}
}
@@ -1107,12 +1174,10 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* even if we have already sent out EAPOL-Key 3/4.
*/
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "Process SNonce update from STA "
- "based on retransmitted EAPOL-Key "
- "1/4");
+ "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
- sm->alt_snonce_valid = TRUE;
+ sm->alt_snonce_valid = true;
os_memcpy(sm->alt_replay_counter,
sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
@@ -1138,12 +1203,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key->replay_counter) &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "ignore retransmitted EAPOL-Key %s - "
- "SNonce did not change", msgtxt);
+ "ignore retransmitted EAPOL-Key %s - SNonce did not change",
+ msgtxt);
} else {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "received EAPOL-Key %s with "
- "unexpected replay counter", msgtxt);
+ "received EAPOL-Key %s with unexpected replay counter",
+ msgtxt);
}
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (!sm->key_replay[i].valid)
@@ -1174,8 +1239,7 @@ continue_processing:
(!sm->update_snonce ||
sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1190,9 +1254,8 @@ continue_processing:
* Counter update and the station will be allowed to
* continue.
*/
- wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
- "collect more entropy for random number "
- "generation");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Reject 4-way handshake to collect more entropy for random number generation");
random_mark_pool_ready();
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1203,8 +1266,7 @@ continue_processing:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
!sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 4/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1213,8 +1275,7 @@ continue_processing:
if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
|| !sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/2 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
sm->wpa_ptk_group_state);
return;
}
@@ -1248,7 +1309,7 @@ continue_processing:
}
#endif /* CONFIG_FILS */
- sm->MICVerified = FALSE;
+ sm->MICVerified = false;
if (sm->PTK_valid && !sm->update_snonce) {
if (mic_len &&
wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
@@ -1281,7 +1342,7 @@ continue_processing:
#ifdef TEST_FUZZ
continue_fuzz:
#endif /* TEST_FUZZ */
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
}
@@ -1293,8 +1354,7 @@ continue_processing:
WPA_REPLAY_COUNTER_LEN);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key request with "
- "invalid MIC");
+ "received EAPOL-Key request with invalid MIC");
return;
}
@@ -1310,8 +1370,7 @@ continue_processing:
return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for new "
- "4-Way Handshake");
+ "received EAPOL-Key Request for new 4-Way Handshake");
wpa_request_new_ptk(sm);
} else if (key_data_length > 0 &&
wpa_parse_kde_ies(key_data, key_data_length,
@@ -1319,10 +1378,13 @@ continue_processing:
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for GTK "
- "rekeying");
+ "received EAPOL-Key Request for GTK rekeying");
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
- wpa_rekey_gtk(wpa_auth, NULL);
+ if (wpa_auth_gtk_rekey_in_process(wpa_auth))
+ wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG,
+ "skip new GTK rekey - already in process");
+ else
+ wpa_rekey_gtk(wpa_auth, NULL);
}
} else {
/* Do not allow the same key replay counter to be reused. */
@@ -1353,12 +1415,12 @@ continue_processing:
os_free(sm->last_rx_eapol_key);
sm->last_rx_eapol_key = os_memdup(data, data_len);
- if (sm->last_rx_eapol_key == NULL)
+ if (!sm->last_rx_eapol_key)
return;
sm->last_rx_eapol_key_len = data_len;
sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
- sm->EAPOLKeyReceived = TRUE;
+ sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
@@ -1421,7 +1483,7 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
sm->pending_1_of_4_timeout = 0;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
- sm->TimeoutEvt = TRUE;
+ sm->TimeoutEvt = true;
wpa_sm_step(sm);
}
@@ -1432,6 +1494,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
size_t len, mic_len, keyhdrlen;
@@ -1460,15 +1523,14 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
- wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
- "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
- "encr=%d)",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
version,
(key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
(key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
(key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
(key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
- pairwise, (unsigned long) kde_len, keyidx, encr);
+ pairwise, kde_len, keyidx, encr);
key_data_len = kde_len;
@@ -1486,9 +1548,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
- if (hdr == NULL)
+ if (!hdr)
return;
- hdr->version = wpa_auth->conf.eapol_version;
+ hdr->version = conf->eapol_version;
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
@@ -1504,7 +1566,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
WPA_PUT_BE16(key->key_info, key_info);
- alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+ alg = pairwise ? sm->pairwise : conf->wpa_group;
if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
WPA_PUT_BE16(key->key_length, 0);
else
@@ -1521,7 +1583,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
- sm->key_replay[0].valid = TRUE;
+ sm->key_replay[0].valid = true;
if (nonce)
os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
@@ -1558,7 +1620,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
- if (buf == NULL) {
+ if (!buf) {
os_free(hdr);
return;
}
@@ -1575,8 +1637,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_printf(MSG_DEBUG,
- "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
- (unsigned int) sm->PTK.kek_len);
+ "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)",
+ sm->PTK.kek_len);
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
@@ -1610,8 +1672,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (key_info & WPA_KEY_INFO_MIC) {
if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTK not valid when sending EAPOL-Key "
- "frame");
+ "PTK not valid when sending EAPOL-Key frame");
os_free(hdr);
return;
}
@@ -1624,9 +1685,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
- drand48() <
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+ conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
+ drand48() < conf->corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
key_mic[0]++;
@@ -1634,8 +1694,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_TESTING_OPTIONS */
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
- 1);
+ wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
sm->pairwise_set);
os_free(hdr);
@@ -1652,7 +1711,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
u32 ctr;
- if (sm == NULL)
+ if (!sm)
return;
__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
@@ -1672,8 +1731,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#ifdef TEST_FUZZ
timeout_ms = 1;
#endif /* TEST_FUZZ */
- wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %u)", timeout_ms, ctr);
+ wpa_printf(MSG_DEBUG,
+ "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
+ timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1710,13 +1770,21 @@ static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
void wpa_remove_ptk(struct wpa_state_machine *sm)
{
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+ wpa_auth_remove_ptksa(sm->wpa_auth, sm->addr, sm->pairwise);
+
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
- 0))
+ 0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
"RSN: PTK removal from the driver failed");
- sm->pairwise_set = FALSE;
+ if (sm->use_ext_key_id &&
+ wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+ 0, KEY_FLAG_PAIRWISE))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK Key ID 1 removal from the driver failed");
+ sm->pairwise_set = false;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1725,7 +1793,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
{
int remove_ptk = 1;
- if (sm == NULL)
+ if (!sm)
return -1;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1745,7 +1813,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
break;
case WPA_DEAUTH:
case WPA_DISASSOC:
- sm->DeauthenticationRequest = TRUE;
+ sm->DeauthenticationRequest = true;
#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->PMK, 0, sizeof(sm->PMK));
sm->pmk_len = 0;
@@ -1765,32 +1833,48 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
* sure that the WPA state machines gets initialized
* properly at this point.
*/
- wpa_printf(MSG_DEBUG, "WPA state machine had not been "
- "started - initialize now");
+ wpa_printf(MSG_DEBUG,
+ "WPA state machine had not been started - initialize now");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
+ break;
+ }
+
+ if (!sm->use_ext_key_id &&
+ sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
break;
}
+
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+
if (sm->GUpdateStationKeys) {
/*
* Reauthentication cancels the pending group key
* update for this STA.
*/
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->PtkGroupInit = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->PtkGroupInit = true;
}
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
break;
case WPA_ASSOC_FT:
#ifdef CONFIG_IEEE80211R_AP
- wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
- "after association");
- wpa_ft_install_ptk(sm);
+ wpa_printf(MSG_DEBUG,
+ "FT: Retry PTK configuration after association");
+ wpa_ft_install_ptk(sm, 1);
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
@@ -1810,7 +1894,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
break;
#endif /* CONFIG_FILS */
case WPA_DRV_STA_REMOVED:
- sm->tk_already_set = FALSE;
+ sm->tk_already_set = false;
return 0;
}
@@ -1818,10 +1902,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
(event == WPA_AUTH || event == WPA_ASSOC))
@@ -1829,7 +1911,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
#endif /* CONFIG_FILS */
if (remove_ptk) {
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (event != WPA_REAUTH_EAPOL)
@@ -1841,7 +1923,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
* wpa_sm_step() is already running - avoid recursive call to
* it by making the existing loop process the new update.
*/
- sm->changed = TRUE;
+ sm->changed = true;
return 0;
}
return wpa_sm_step(sm);
@@ -1854,18 +1936,18 @@ SM_STATE(WPA_PTK, INITIALIZE)
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->keycount = 0;
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
+ sm->PInitAKeys = false;
if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
* Local AA > Remote AA)) */) {
- sm->Pair = TRUE;
+ sm->Pair = true;
}
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
wpa_remove_ptk(sm);
@@ -1885,7 +1967,7 @@ SM_STATE(WPA_PTK, DISCONNECT)
u16 reason = sm->disconnect_reason;
SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
- sm->Disconnect = FALSE;
+ sm->Disconnect = false;
sm->disconnect_reason = 0;
if (!reason)
reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
@@ -1896,7 +1978,7 @@ SM_STATE(WPA_PTK, DISCONNECT)
SM_STATE(WPA_PTK, DISCONNECTED)
{
SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
- sm->DeauthenticationRequest = FALSE;
+ sm->DeauthenticationRequest = false;
}
@@ -1904,11 +1986,11 @@ SM_STATE(WPA_PTK, AUTHENTICATION)
{
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
1);
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
- sm->AuthenticationRequest = FALSE;
+ sm->AuthenticationRequest = false;
}
@@ -1924,23 +2006,23 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
* GMK and Counter here to improve their strength if there was not
* enough entropy available immediately after system startup.
*/
- wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
- "station");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Re-initialize GMK/Counter on first station");
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "to proceed - reject first 4-way handshake");
- group->reject_4way_hs_for_entropy = TRUE;
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
+ group->reject_4way_hs_for_entropy = true;
} else {
- group->first_sta_seen = TRUE;
- group->reject_4way_hs_for_entropy = FALSE;
+ group->first_sta_seen = true;
+ group->reject_4way_hs_for_entropy = false;
}
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;
+ group->first_sta_seen = false;
+ group->reject_4way_hs_for_entropy = true;
}
}
@@ -1950,7 +2032,7 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
- sm->ReAuthenticationRequest = FALSE;
+ sm->ReAuthenticationRequest = false;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1962,9 +2044,9 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
* stronger protection against potential precomputation attacks.
*/
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
- "ANonce.");
- sm->Disconnect = TRUE;
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to get random data for ANonce.");
+ sm->Disconnect = true;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
@@ -1982,7 +2064,7 @@ static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR,
"WPA: Failed to get random data for ANonce");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return -1;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
@@ -2009,7 +2091,7 @@ SM_STATE(WPA_PTK, INITPMK)
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
wpa_printf(MSG_DEBUG,
"DPP: No PMKSA cache entry for STA - reject connection");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
return;
#endif /* CONFIG_DPP */
@@ -2020,14 +2102,14 @@ SM_STATE(WPA_PTK, INITPMK)
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
- wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
- "(MSK len=%lu PMK len=%u)", (unsigned long) len,
- pmk_len);
+ wpa_printf(MSG_DEBUG,
+ "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
+ len, pmk_len);
if (len < pmk_len) {
wpa_printf(MSG_DEBUG,
- "WPA: MSK not long enough (%u) to create PMK (%u)",
- (unsigned int) len, (unsigned int) pmk_len);
- sm->Disconnect = TRUE;
+ "WPA: MSK not long enough (%zu) to create PMK (%u)",
+ len, pmk_len);
+ sm->Disconnect = true;
return;
}
os_memcpy(sm->PMK, msk, pmk_len);
@@ -2046,21 +2128,21 @@ SM_STATE(WPA_PTK, INITPMK)
} else {
wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
sm->wpa_auth->cb->get_msk);
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return;
}
forced_memzero(msk, sizeof(msk));
sm->req_replay_counter_used = 0;
- /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+ /* IEEE 802.11i does not set keyRun to false, but not doing this
* will break reauthentication since EAPOL state machines may not be
* get into AUTHENTICATING state that clears keyRun before WPA state
* machine enters AUTHENTICATION2 state and goes immediately to INITPMK
* state and takes PMK from the previously used AAA Key. This will
* eventually fail in 4-Way Handshake because Supplicant uses PMK
- * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+ * derived from the new AAA Key. Setting keyRun = false here seems to
* be good workaround for this issue. */
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, false);
}
@@ -2101,9 +2183,9 @@ SM_STATE(WPA_PTK, PTKSTART)
size_t pmkid_len = 0;
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
- sm->PTKRequest = FALSE;
- sm->TimeoutEvt = FALSE;
- sm->alt_snonce_valid = FALSE;
+ sm->PTKRequest = false;
+ sm->TimeoutEvt = false;
+ sm->alt_snonce_valid = false;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
@@ -2170,7 +2252,6 @@ SM_STATE(WPA_PTK, PTKSTART)
wpa_printf(MSG_DEBUG,
"FT: No PMKID in message 1/4 when using FT protocol");
pmkid = NULL;
- pmkid_len = 0;
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
@@ -2200,6 +2281,8 @@ SM_STATE(WPA_PTK, PTKSTART)
&pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
}
}
+ if (!pmkid)
+ pmkid_len = 0;
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
sm->ANonce, pmkid, pmkid_len, 0, 0);
@@ -2208,10 +2291,18 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
+ int akmp;
+
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2224,7 +2315,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
sm->pmk_r1_name,
ptk, ptk_name,
sm->wpa_key_mgmt,
- sm->pairwise);
+ sm->pairwise,
+ kdk_len);
}
return wpa_auth_derive_ptk_ft(sm, ptk);
}
@@ -2237,9 +2329,12 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->wpa_key_mgmt;
+ if (force_sha256)
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len, kdk_len);
}
@@ -2254,17 +2349,24 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
size_t ick_len;
int res;
u8 fils_ft[FILS_FT_MAX_LEN];
- size_t fils_ft_len = 0;
+ size_t fils_ft_len = 0, kdk_len;
+
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
snonce, anonce, dhss, dhss_len,
&sm->PTK, ick, &ick_len,
sm->wpa_key_mgmt, sm->pairwise,
- fils_ft, &fils_ft_len);
+ fils_ft, &fils_ft_len, kdk_len);
if (res < 0)
return res;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
#ifdef CONFIG_IEEE80211R_AP
if (fils_ft_len) {
@@ -2272,7 +2374,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_auth_config *conf = &wpa_auth->conf;
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
- size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
conf->ssid, conf->ssid_len,
@@ -2283,10 +2384,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
forced_memzero(fils_ft, sizeof(fils_ft));
@@ -2453,9 +2550,9 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
wpa_printf(MSG_DEBUG,
- "FILS: Unexpected Key-Auth length %d (expected %d)",
+ "FILS: Unexpected Key-Auth length %d (expected %zu)",
elems.fils_key_confirm_len,
- (int) sm->fils_key_auth_len);
+ sm->fils_key_auth_len);
return -1;
}
@@ -2648,8 +2745,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
u8 *gtk, dummy_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
+ size_t plain_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
- plain = wpabuf_alloc(1000);
+ plain_len = 1000 + ieee80211w_kde_len(sm);
+ if (conf->transition_disable)
+ plain_len += 2 + RSN_SELECTOR_LEN + 1;
+ plain = wpabuf_alloc(plain_len);
if (!plain)
return NULL;
@@ -2678,8 +2780,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2697,11 +2798,18 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
- /* IGTK KDE */
+ /* IGTK KDE and BIGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
+ if (conf->transition_disable) {
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+ wpabuf_put(plain, tmp2 - tmp);
+ }
+
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
#ifdef CONFIG_OCV
@@ -2715,6 +2823,15 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
wpabuf_clear_free(plain);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_fils_assoc);
+ ci.frequency = conf->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -2747,11 +2864,14 @@ int fils_set_tk(struct wpa_state_machine *sm)
wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
- sm->tk_already_set = TRUE;
+ sm->tk_already_set = true;
+
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
return 0;
}
@@ -2779,8 +2899,8 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
pos += wpabuf_len(plain);
- wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
- (unsigned int) wpabuf_len(plain));
+ wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
+ wpabuf_len(plain));
wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
@@ -2819,10 +2939,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
- sm->update_snonce = FALSE;
+ sm->EAPOLKeyReceived = false;
+ sm->update_snonce = false;
os_memset(&PTK, 0, sizeof(PTK));
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -2836,7 +2957,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
psk_found = 1;
#ifdef CONFIG_IEEE80211R_AP
@@ -2856,7 +2977,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk_len = sm->pmksa->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+ owe_ptk_workaround == 2) < 0)
break;
if (mic_len &&
@@ -2880,6 +3002,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+ owe_ptk_workaround == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try PTK derivation workaround with SHA256");
+ owe_ptk_workaround = 2;
+ continue;
+ }
+#endif /* CONFIG_OWE */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
@@ -2922,7 +3054,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
eapol_key_ie_len = kde.wpa_ie_len;
}
ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
+ if (!sm->wpa_ie ||
wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
eapol_key_ie, eapol_key_ie_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -2938,11 +3070,28 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+ if ((!sm->rsnxe && kde.rsnxe) ||
+ (sm->rsnxe && !kde.rsnxe) ||
+ (sm->rsnxe && kde.rsnxe &&
+ (sm->rsnxe_len != kde.rsnxe_len ||
+ os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
+ sm->rsnxe, sm->rsnxe_len);
+ wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
+ kde.rsnxe, kde.rsnxe_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -2956,10 +3105,21 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
&tx_seg1_idx) < 0)
return;
- if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-m2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -2991,6 +3151,24 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && kde.dpp_kde) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: peer Protocol Version %u Flags 0x%x",
+ kde.dpp_kde[0], kde.dpp_kde[1]);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_auth->conf.dpp_pfs != 2 &&
+ (kde.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) &&
+ !sm->dpp_z) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211R_AP
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
/*
@@ -3000,10 +3178,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKR1Name mismatch in FT 4-way "
- "handshake");
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
- "Supplicant",
+ "PMKR1Name mismatch in FT 4-way handshake");
+ wpa_hexdump(MSG_DEBUG,
+ "FT: PMKR1Name from Supplicant",
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -3022,7 +3199,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && sm->PMK != pmk) {
/* PSK may have changed from the previous choice, so update
* state machine data based on whatever PSK was selected here.
*/
@@ -3030,11 +3207,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->pmk_len = PMK_LEN;
}
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
- sm->PTK_valid = TRUE;
+ sm->PTK_valid = true;
}
@@ -3045,26 +3222,31 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
}
-#ifdef CONFIG_IEEE80211W
-
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
+ size_t len = 0;
+
if (sm->mgmt_frame_prot) {
- size_t len;
- len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+ len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ }
+ if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
}
- return 0;
+ return len;
}
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
+ struct wpa_bigtk_kde bigtk;
struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN];
- size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+ size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (!sm->mgmt_frame_prot)
return pos;
@@ -3077,8 +3259,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -3090,24 +3271,32 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
- return pos;
-}
-
-#else /* CONFIG_IEEE80211W */
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
- return 0;
-}
+ if (!conf->beacon_prot)
+ return pos;
+ bigtk.keyid[0] = gsm->GN_bigtk;
+ bigtk.keyid[1] = 0;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+ os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+ else
+ os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+ os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(bigtk.bigtk, len) < 0)
+ return pos;
+ }
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+ (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
return pos;
}
-#endif /* CONFIG_IEEE80211W */
-
static int ocv_oci_len(struct wpa_state_machine *sm)
{
@@ -3118,7 +3307,9 @@ static int ocv_oci_len(struct wpa_state_machine *sm)
return 0;
}
-static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos,
+ unsigned int freq)
{
#ifdef CONFIG_OCV
struct wpa_channel_info ci;
@@ -3131,6 +3322,14 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
"Failed to get channel info for OCI element");
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (freq) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %u MHz",
+ ci.frequency, freq);
+ ci.frequency = freq;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return ocv_insert_oci_kde(&ci, argpos);
#else /* CONFIG_OCV */
@@ -3139,64 +3338,131 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
}
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *elem;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+ old_buf, *len);
+ buf = os_malloc(*len + ie_len);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, old_buf, *len);
+ elem = get_ie(buf, *len, eid);
+ if (elem) {
+ u8 elem_len = 2 + elem[1];
+
+ os_memmove((void *) elem, elem + elem_len,
+ *len - (elem - buf) - elem_len);
+ *len -= elem_len;
+ }
+ os_memcpy(buf + *len, ie, ie_len);
+ *len += ie_len;
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+ buf, *len);
+
+ return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
- size_t gtk_len, kde_len;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+ size_t gtk_len, kde_len, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int secure, gtkidx, encr = 0;
+ u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+ u8 hdr[2];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
- sm->TimeoutEvt = FALSE;
+ sm->TimeoutEvt = false;
sm->TimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->TimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key msg 3/4 */
return;
}
- if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
wpa_ie = sm->wpa_auth->wpa_ie;
wpa_ie_len = sm->wpa_auth->wpa_ie_len;
- if (sm->wpa == WPA_VERSION_WPA &&
- (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->rsne_override_eapol_set) {
+ wpa_ie_buf2 = replace_ie(
+ "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+ conf->rsne_override_eapol,
+ conf->rsne_override_eapol_len);
+ if (!wpa_ie_buf2)
+ goto done;
+ wpa_ie = wpa_ie_buf2;
+ }
+ if (conf->rsnxe_override_eapol_set) {
+ wpa_ie_buf = replace_ie(
+ "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+ conf->rsnxe_override_eapol,
+ conf->rsnxe_override_eapol_len);
+ if (!wpa_ie_buf)
+ goto done;
+ wpa_ie = wpa_ie_buf;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake");
if (sm->wpa == WPA_VERSION_WPA2) {
+ if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+ wpa_auth_set_key(sm->wpa_auth, 0,
+ wpa_cipher_to_alg(sm->pairwise),
+ sm->addr,
+ sm->keyidx_active, sm->PTK.tk,
+ wpa_cipher_key_len(sm->pairwise),
+ KEY_FLAG_PAIRWISE_RX)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
/* WPA2 send GTK in the 4-way handshake */
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
+ if (conf->disable_gtk ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0)
- return;
+ goto done;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -3204,7 +3470,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -3216,13 +3481,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3235,9 +3503,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
#endif /* CONFIG_P2P */
+
+ if (conf->transition_disable)
+ kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+#endif /* CONFIG_DPP2 */
+
kde = os_malloc(kde_len);
- if (kde == NULL)
- return;
+ if (!kde)
+ goto done;
pos = kde;
os_memcpy(pos, wpa_ie, wpa_ie_len);
@@ -3250,34 +3527,34 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
+ goto done;
}
pos -= wpa_ie_len;
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
- hdr[0] = keyidx & 0x03;
- hdr[1] = 0;
+ hdr[0] = gtkidx & 0x03;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
- os_free(kde);
- return;
- }
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
+ goto done;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -3291,13 +3568,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
+ goto done;
}
pos += res;
@@ -3320,41 +3596,75 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
os_memcpy(addr, sm->ip_addr, 4);
- os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
- os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+ os_memcpy(addr + 4, conf->ip_addr_mask, 4);
+ os_memcpy(addr + 8, conf->ip_addr_go, 4);
pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
addr, sizeof(addr), NULL, 0);
}
#endif /* CONFIG_P2P */
+ if (conf->transition_disable)
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
+ u8 payload[2];
+
+ payload[0] = DPP_VERSION; /* Protocol Version */
+ payload[1] = 0; /* Flags */
+ if (conf->dpp_pfs == 0)
+ payload[1] |= DPP_KDE_PFS_ALLOWED;
+ else if (conf->dpp_pfs == 1)
+ payload[1] |= DPP_KDE_PFS_ALLOWED |
+ DPP_KDE_PFS_REQUIRED;
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_DPP,
+ payload, sizeof(payload), NULL, 0);
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) |
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
+done:
os_free(kde);
+ os_free(wpa_ie_buf);
+ os_free(wpa_ie_buf2);
}
SM_STATE(WPA_PTK, PTKINITDONE)
{
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
if (sm->Pair) {
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+ sm->keyidx_active, NULL, 0,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+ else
+ res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+ 0, sm->PTK.tk, klen,
+ KEY_FLAG_PAIRWISE_RX_TX);
+ if (res) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
+ sm->pairwise_set = true;
wpa_auth_set_ptk_rekey_timer(sm);
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -3374,15 +3684,18 @@ SM_STATE(WPA_PTK, PTKINITDONE)
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
1);
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable,
+ false);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, true);
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = TRUE;
+ sm->PInitAKeys = true;
else
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+ wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO, "EAPOL-4WAY-HS-COMPLETED "
+ MACSTR, MAC2STR(sm->addr));
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
@@ -3393,6 +3706,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
SM_STEP(WPA_PTK)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_auth_config *conf = &wpa_auth->conf;
if (sm->Init)
SM_ENTER(WPA_PTK, INITIALIZE);
@@ -3427,8 +3741,8 @@ SM_STEP(WPA_PTK)
break;
case WPA_PTK_AUTHENTICATION2:
if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
- wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyRun) > 0)
+ wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyRun))
SM_ENTER(WPA_PTK, INITPMK);
else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
@@ -3438,8 +3752,8 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, INITPMK);
break;
case WPA_PTK_INITPMK:
- if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyAvailable) > 0) {
+ if (wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyAvailable)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_DPP
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
@@ -3447,13 +3761,13 @@ SM_STEP(WPA_PTK)
#endif /* CONFIG_DPP */
} else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"INITPMK - keyAvailable = false");
SM_ENTER(WPA_PTK, DISCONNECT);
}
break;
case WPA_PTK_INITPSK:
- if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+ if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
@@ -3461,7 +3775,7 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
} else {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3471,13 +3785,13 @@ SM_STEP(WPA_PTK)
if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
- else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -3501,14 +3815,15 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count ||
- (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ conf->wpa_pairwise_update_count ||
+ (conf->wpa_disable_eapol_key_retries &&
sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3525,7 +3840,7 @@ SM_STATE(WPA_PTK_GROUP, IDLE)
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->GTimeoutCtr = 0;
}
@@ -3539,24 +3854,24 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->GTimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
return;
}
- if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
+ if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
- sm->TimeoutEvt = FALSE;
+ sm->PInitAKeys = false;
+ sm->TimeoutEvt = false;
/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
@@ -3565,8 +3880,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -3579,7 +3893,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return;
kde = pos = kde_buf;
@@ -3588,7 +3902,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return;
}
@@ -3612,8 +3927,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
-#ifdef CONFIG_OCV
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+#ifdef CONFIG_OCV
const u8 *key_data, *mic;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
@@ -3623,7 +3938,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
#endif /* CONFIG_OCV */
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
#ifdef CONFIG_OCV
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -3654,7 +3969,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
return;
}
@@ -3665,9 +3980,15 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
return;
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-g2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -3675,13 +3996,13 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
}
@@ -3690,8 +4011,9 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR)
SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->Disconnect = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->Disconnect = true;
+ sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake failed (%s) after %u tries",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
@@ -3703,7 +4025,7 @@ SM_STEP(WPA_PTK_GROUP)
{
if (sm->Init || sm->PtkGroupInit) {
SM_ENTER(WPA_PTK_GROUP, IDLE);
- sm->PtkGroupInit = FALSE;
+ sm->PtkGroupInit = false;
} else switch (sm->wpa_ptk_group_state) {
case WPA_PTK_GROUP_IDLE:
if (sm->GUpdateStationKeys ||
@@ -3735,7 +4057,9 @@ SM_STEP(WPA_PTK_GROUP)
static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
+ size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3746,10 +4070,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
-#ifdef CONFIG_IEEE80211W
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- size_t len;
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
@@ -3759,7 +4081,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], len);
}
-#endif /* CONFIG_IEEE80211W */
+
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ conf->beacon_prot) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->BIGTK[group->GN_bigtk - 6], len) < 0)
+ ret = -1;
+ wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+ group->BIGTK[group->GN_bigtk - 6], len);
+ }
return ret;
}
@@ -3768,19 +4102,20 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "GTK_INIT (VLAN-ID %d)", group->vlan_id);
- group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = false; /* GInit is not cleared here; avoid loop */
group->wpa_group_state = WPA_GROUP_GTK_INIT;
/* GTK[0..N] = 0 */
os_memset(group->GTK, 0, sizeof(group->GTK));
group->GN = 1;
group->GM = 2;
-#ifdef CONFIG_IEEE80211W
group->GN_igtk = 4;
group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
+ group->GN_bigtk = 6;
+ group->GM_bigtk = 7;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3794,7 +4129,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
return 0;
}
if (sm->GUpdateStationKeys) {
@@ -3804,8 +4139,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
* station needs to be counted here anyway.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "GUpdateStationKeys was already set when "
- "marking station for GTK rekeying");
+ "GUpdateStationKeys was already set when marking station for GTK rekeying");
}
/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
@@ -3813,7 +4147,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
return 0;
sm->group->GKeyDoneStations++;
- sm->GUpdateStationKeys = TRUE;
+ sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
return 0;
@@ -3824,7 +4158,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
- if (sm == NULL || sm->is_wnmsleep)
+ if (!sm || sm->is_wnmsleep)
return;
wpa_group_update_sta(sm, NULL);
@@ -3840,6 +4174,7 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
@@ -3858,6 +4193,14 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return 0;
pos += 8;
os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(pos, gsm->GTK_len) < 0)
+ return 0;
+ }
pos += gsm->GTK_len;
wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
@@ -3869,9 +4212,9 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
}
-#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
@@ -3889,6 +4232,14 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use
+ * of IGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
@@ -3898,7 +4249,45 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return pos - start;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /*
+ * BIGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+ *pos++ = 2 + 6 + len;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+ return 0;
+ pos += 6;
+
+ os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
+ pos += len;
+
+ wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_bigtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+ gsm->BIGTK[gsm->GN_bigtk - 6], len);
+
+ return pos - start;
+}
+
#endif /* CONFIG_WNM_AP */
@@ -3907,27 +4296,29 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
{
int tmp;
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYS (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYS;
- group->GTKReKey = FALSE;
+ group->GTKReKey = false;
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
wpa_gtk_update(wpa_auth, group);
if (group->GKeyDoneStations) {
- wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
- "GKeyDoneStations=%d when starting new GTK rekey",
+ wpa_printf(MSG_DEBUG,
+ "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
@@ -3940,29 +4331,37 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(conf->wpa_group),
broadcast_ether_addr, group->GN,
- group->GTK[group->GN - 1], group->GTK_len) < 0)
+ group->GTK[group->GN - 1], group->GTK_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
- alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4], len) < 0)
+ group->IGTK[group->GN_igtk - 4], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ ret = -1;
+
+ if (ret == 0 && conf->beacon_prot &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_bigtk,
+ group->BIGTK[group->GN_bigtk - 6], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -3972,9 +4371,9 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->group == ctx) {
wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
- " for discconnection due to fatal failure",
+ " for disconnection due to fatal failure",
MAC2STR(sm->addr));
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
}
return 0;
@@ -3984,8 +4383,9 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state FATAL_FAILURE");
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
}
@@ -3994,9 +4394,10 @@ static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
@@ -4032,7 +4433,7 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
static int wpa_sm_step(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
if (sm->in_step_loop) {
@@ -4048,8 +4449,8 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
if (sm->pending_deinit)
break;
- sm->changed = FALSE;
- sm->wpa_auth->group->changed = FALSE;
+ sm->changed = false;
+ sm->wpa_auth->group->changed = false;
SM_STEP_RUN(WPA_PTK);
if (sm->pending_deinit)
@@ -4062,8 +4463,9 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
sm->in_step_loop = 0;
if (sm->pending_deinit) {
- wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Completing pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
wpa_free_sta_sm(sm);
return 1;
}
@@ -4080,7 +4482,7 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
void wpa_auth_sm_notify(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
}
@@ -4091,7 +4493,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
int tmp, i;
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return;
group = wpa_auth->group;
@@ -4100,11 +4502,12 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4123,6 +4526,7 @@ static const char * wpa_bool_txt(int val)
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
{
+ struct wpa_auth_config *conf;
int len = 0, ret;
char pmkid_txt[PMKID_LEN * 2 + 1];
#ifdef CONFIG_RSN_PREAUTH
@@ -4131,8 +4535,9 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
const int preauth = 0;
#endif /* CONFIG_RSN_PREAUTH */
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return len;
+ conf = &wpa_auth->conf;
ret = os_snprintf(buf + len, buflen - len,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -4140,8 +4545,8 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNAEnabled=%s\n"
"dot11RSNAPreauthenticationEnabled=%s\n",
wpa_bool_txt(preauth),
- wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
- wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+ wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
+ wpa_bool_txt(conf->rsn_preauth));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -4176,10 +4581,10 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNA4WayHandshakeFailures=%u\n"
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
- !!wpa_auth->conf.wpa_strict_rekey,
- wpa_auth->conf.wpa_group_update_count,
- wpa_auth->conf.wpa_pairwise_update_count,
- wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+ !!conf->wpa_strict_rekey,
+ conf->wpa_group_update_count,
+ conf->wpa_pairwise_update_count,
+ wpa_cipher_key_len(conf->wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -4215,7 +4620,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
int len = 0, ret;
u32 pairwise = 0;
- if (sm == NULL)
+ if (!sm)
return 0;
/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
@@ -4296,7 +4701,7 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return -1;
return sm->wpa_key_mgmt;
}
@@ -4304,7 +4709,7 @@ int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa;
}
@@ -4329,7 +4734,7 @@ int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry)
{
- if (sm == NULL || sm->pmksa != entry)
+ if (!sm || sm->pmksa != entry)
return -1;
sm->pmksa = NULL;
return 0;
@@ -4352,7 +4757,7 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
*len = wpa_auth->wpa_ie_len;
return wpa_auth->wpa_ie;
@@ -4363,7 +4768,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol)
{
- if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+ if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
@@ -4399,7 +4804,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
int session_timeout,
struct eapol_state_machine *eapol)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
@@ -4442,7 +4847,7 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int session_timeout, int akmp)
{
- if (wpa_auth->conf.disable_pmksa_caching)
+ if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
@@ -4460,7 +4865,7 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
{
struct rsn_pmksa_cache_entry *pmksa;
- if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ if (!wpa_auth || !wpa_auth->pmksa)
return;
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
if (pmksa) {
@@ -4626,13 +5031,13 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL || wpa_auth->group == NULL)
+ if (!wpa_auth || !wpa_auth->group)
return NULL;
wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
vlan_id);
group = wpa_group_init(wpa_auth, vlan_id, 0);
- if (group == NULL)
+ if (!group)
return NULL;
group->next = wpa_auth->group->next;
@@ -4652,7 +5057,7 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4662,9 +5067,9 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4693,7 +5098,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
struct wpa_group *group;
int ret = 0;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4703,7 +5108,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL)
+ if (!group)
return -1;
wpa_printf(MSG_DEBUG,
@@ -4738,7 +5143,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
{
struct wpa_group *group;
- if (sm == NULL || sm->wpa_auth == NULL)
+ if (!sm || !sm->wpa_auth)
return 0;
group = sm->wpa_auth->group;
@@ -4748,9 +5153,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4760,8 +5165,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
- wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
- "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
+ " to use group state machine for VLAN ID %d",
+ MAC2STR(sm->addr), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -4774,7 +5180,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack)
{
- if (wpa_auth == NULL || sm == NULL)
+ if (!wpa_auth || !sm)
return;
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
" ack=%d", MAC2STR(sm->addr), ack);
@@ -4790,8 +5196,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
* the station has received the frame.
*/
int timeout_ms = eapol_key_timeout_subseq;
- wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
- "timeout by %u ms because of acknowledged frame",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
timeout_ms);
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
eloop_register_timeout(timeout_ms / 1000,
@@ -4811,7 +5217,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
int wpa_auth_uses_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
}
@@ -4819,7 +5225,7 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm)
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
}
@@ -4828,7 +5234,7 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
{
- if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+ if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
return -1;
os_memcpy(addr, sm->ip_addr, 4);
return 0;
@@ -4904,7 +5310,7 @@ int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
conf->r0_key_holder_len,
- NULL, NULL, buf, len, NULL, 0);
+ NULL, NULL, buf, len, NULL, 0, 0);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -4950,6 +5356,14 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
#endif /* CONFIG_DPP2 */
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.transition_disable = val;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
@@ -4979,16 +5393,16 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t gtk_len, kde_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
+ u8 hdr[2];
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
/* Use 0 RSC */
@@ -5001,6 +5415,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
@@ -5012,7 +5428,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -5020,7 +5436,6 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -5032,13 +5447,16 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -5048,7 +5466,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
#endif /* CONFIG_IEEE80211R_AP */
kde = os_malloc(kde_len);
- if (kde == NULL)
+ if (!kde)
return -1;
pos = kde;
@@ -5062,8 +5480,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return -1;
}
@@ -5071,14 +5489,18 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
- hdr[0] = keyidx & 0x03;
- hdr[1] = 0;
+ hdr[0] = gtkidx & 0x03;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
@@ -5086,8 +5508,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) {
os_free(kde);
return -1;
}
@@ -5095,9 +5516,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -5111,11 +5530,11 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
os_free(kde);
return -1;
}
@@ -5143,7 +5562,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
return 0;
}
@@ -5154,12 +5573,11 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t kde_len;
u8 *gtk;
@@ -5174,7 +5592,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return -1;
kde = pos = kde_buf;
@@ -5182,7 +5600,6 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
-#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
if (pos - opos >=
@@ -5191,8 +5608,8 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
-#endif /* CONFIG_IEEE80211W */
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return -1;
}
@@ -5227,4 +5644,46 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
}
+
+int wpa_auth_rekey_ptk(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm)
+{
+ if (!wpa_auth || !sm)
+ return -1;
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+ wpa_request_new_ptk(sm);
+ wpa_sm_step(sm);
+ return 0;
+}
+
+
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.ft_rsnxe_used = val;
+}
+
+
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq)
+{
+ if (!wpa_auth)
+ return;
+ switch (frame) {
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3:
+ wpa_auth->conf.oci_freq_override_eapol_m3 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1:
+ wpa_auth->conf.oci_freq_override_eapol_g1 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC:
+ wpa_auth->conf.oci_freq_override_ft_assoc = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC:
+ wpa_auth->conf.oci_freq_override_fils_assoc = freq;
+ break;
+ }
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/contrib/wpa/src/ap/wpa_auth.h b/contrib/wpa/src/ap/wpa_auth.h
index a348bc25abd9..fe47723b9e6b 100644
--- a/contrib/wpa/src/ap/wpa_auth.h
+++ b/contrib/wpa/src/ap/wpa_auth.h
@@ -168,7 +168,9 @@ struct ft_remote_r1kh {
struct wpa_auth_config {
+ void *msg_ctx;
int wpa;
+ int extended_key_id;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
@@ -176,6 +178,7 @@ struct wpa_auth_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -187,11 +190,10 @@ struct wpa_auth_config {
int disable_pmksa_caching;
int okc;
int tx_status;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
+ int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -221,7 +223,28 @@ struct wpa_auth_config {
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
+ u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_eapol_len;
+ u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_eapol_len;
+ u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_ft_len;
+ u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_ft_len;
+ u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
+ u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
+ unsigned int rsne_override_eapol_set:1;
+ unsigned int rsnxe_override_eapol_set:1;
+ unsigned int rsne_override_ft_set:1;
+ unsigned int rsnxe_override_ft_set:1;
+ unsigned int gtk_rsc_override_set:1;
+ unsigned int igtk_rsc_override_set:1;
+ int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
@@ -232,6 +255,24 @@ struct wpa_auth_config {
unsigned int fils_cache_id_set:1;
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
+ int sae_pwe;
+ bool sae_pk;
+
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
+
+ int owe_ptk_workaround;
+ u8 transition_disable;
+#ifdef CONFIG_DPP2
+ int dpp_pfs;
+#endif /* CONFIG_DPP2 */
+
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
};
typedef enum {
@@ -258,7 +299,8 @@ struct wpa_auth_callbacks {
int *vlan_id);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len);
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
@@ -275,8 +317,12 @@ struct wpa_auth_callbacks {
int (*get_sta_tx_params)(void *ctx, const u8 *addr,
int ap_max_chanwidth, int ap_seg1_idx,
int *bandwidth, int *seg1_idx);
+ void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
+ void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
int (*set_vlan)(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan);
int (*get_vlan)(void *ctx, const u8 *sta_addr,
@@ -310,18 +356,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
-enum {
+enum wpa_validate_result {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
- WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
+ WPA_DENIED_OTHER_REASON
};
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int freq,
- const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len);
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -405,14 +454,15 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len);
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
@@ -423,12 +473,21 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout);
+
#endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
@@ -478,8 +537,12 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val);
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
@@ -490,7 +553,23 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
void (*cb)(void *ctx1, void *ctx2),
void *ctx1, void *ctx2);
+int wpa_auth_rekey_ptk(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm);
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
+int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+ const u8 *data, size_t data_len,
+ int encrypt);
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
+
+enum wpa_auth_ocv_override_frame {
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC,
+};
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq);
#endif /* WPA_AUTH_H */
diff --git a/contrib/wpa/src/ap/wpa_auth_ft.c b/contrib/wpa/src/ap/wpa_auth_ft.c
index 696f8d5fa49b..e80086b93d8d 100644
--- a/contrib/wpa/src/ap/wpa_auth_ft.c
+++ b/contrib/wpa/src/ap/wpa_auth_ft.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
@@ -808,7 +809,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len)
+ size_t subelem_len, int rsnxe_used)
{
u8 *pos = buf, *ielen;
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
@@ -826,7 +827,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -836,7 +837,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -951,8 +952,9 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
goto err;
}
- wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
- MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
item = os_zalloc(sizeof(*item));
if (!item)
goto err;
@@ -1471,13 +1473,13 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
}
-static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
- const u8 *spa, const u8 *pmk_r1_name,
- u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
- struct vlan_description *vlan,
- const u8 **identity, size_t *identity_len,
- const u8 **radius_cui, size_t *radius_cui_len,
- int *session_timeout)
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r1_sa *r1;
@@ -1896,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
return;
}
- wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+ wpa_hexdump(MSG_DEBUG, "FT: Temporarily block R0KH-ID",
f_r0kh_id, f_r0kh_id_len);
if (r0kh) {
@@ -1984,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1;
}
if (is_zero_ether_addr(r0kh->addr)) {
- wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is temporarily blocked",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
@@ -1997,9 +1999,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key = r0kh->key;
key_len = sizeof(r0kh->key);
- wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
- "address " MACSTR, MAC2STR(r0kh->addr));
-
if (r0kh->seq->rx.num_last == 0) {
/* A sequence request will be sent out anyway when pull
* response is received. Send it out now to avoid one RTT. */
@@ -2008,6 +2007,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key_len, NULL, 0, NULL, 0, NULL);
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
if (first &&
random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2126,8 +2129,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
pmk_r0_name,
@@ -2138,9 +2139,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
pmk_r1, sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
sm->pmk_r1_name, sm->pairwise, &vlan,
@@ -2149,7 +2147,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
- ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise,
+ 0);
}
@@ -2165,11 +2164,12 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len;
const u8 *key;
size_t key_len;
- u8 keybuf[32];
+ u8 keybuf[WPA_GTK_MAX_LEN];
const u8 *kek;
size_t kek_len;
@@ -2196,12 +2196,30 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ if (conf->disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ }
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
- } else
+ } else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use of GTK
+ * in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ key = keybuf;
+ } else {
key = gsm->GTK[gsm->GN - 1];
+ }
/*
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
@@ -2232,15 +2250,16 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
}
-#ifdef CONFIG_IEEE80211W
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *igtk;
size_t kek_len;
size_t igtk_len;
+ u8 dummy_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2267,8 +2286,19 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = igtk_len;
- if (aes_wrap(kek, kek_len, igtk_len / 8,
- gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ igtk = gsm->IGTK[gsm->GN_igtk - 4];
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ igtk = dummy_igtk;
+ }
+ if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: IGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2279,7 +2309,66 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
*len = subelem_len;
return subelem;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+ const u8 *kek, *bigtk;
+ size_t kek_len;
+ size_t bigtk_len;
+ u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+ * Key[16+8] */
+ subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_BIGTK;
+ *pos++ = subelem_len - 2;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+ pos += 6;
+ *pos++ = bigtk_len;
+ bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ bigtk = dummy_bigtk;
+ }
+ if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: BIGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
@@ -2415,11 +2504,15 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len)
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe)
{
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+ u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
+ size_t rsnxe_len;
+ int rsnxe_used;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2440,6 +2533,32 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
end = pos + max_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsne_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE FT override for MIC calculation");
+ rsnie = sm->wpa_auth->conf.rsne_override_ft;
+ rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
+ if (end - pos < (long int) rsnie_len)
+ return pos;
+ os_memcpy(pos, rsnie, rsnie_len);
+ rsnie = pos;
+ pos += rsnie_len;
+ if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
+ int idx;
+
+ /* Replace all 0xff PMKID with the valid PMKR1Name */
+ for (idx = 0; idx < PMKID_LEN; idx++) {
+ if (rsnie[rsnie_len - 1 - idx] != 0xff)
+ break;
+ }
+ if (idx == PMKID_LEN)
+ os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT ||
((auth_alg == WLAN_AUTH_FILS_SK ||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
@@ -2487,7 +2606,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot) {
u8 *igtk;
size_t igtk_len;
@@ -2510,7 +2628,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
subelem_len += igtk_len;
os_free(igtk);
}
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mgmt_frame_prot && conf->beacon_prot) {
+ u8 *bigtk;
+ size_t bigtk_len;
+ u8 *nbuf;
+
+ bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+ if (!bigtk) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add BIGTK subelement");
+ os_free(subelem);
+ return NULL;
+ }
+ nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+ if (!nbuf) {
+ os_free(subelem);
+ os_free(bigtk);
+ return NULL;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+ subelem_len += bigtk_len;
+ os_free(bigtk);
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2522,6 +2662,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
os_free(subelem);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_ft_assoc);
+ ci.frequency = conf->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
subelem_len += 2 + OCV_OCI_LEN;
nbuf = os_realloc(subelem, subelem_len);
@@ -2546,9 +2695,18 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
anonce = NULL;
snonce = NULL;
}
+ rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->wpa_auth->conf.ft_rsnxe_used) {
+ rsnxe_used = sm->wpa_auth->conf.ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
anonce, snonce, pos, end - pos,
- subelem, subelem_len);
+ subelem, subelem_len, rsnxe_used);
os_free(subelem);
if (res < 0)
return NULL;
@@ -2584,6 +2742,27 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
if (ric_start == pos)
ric_start = NULL;
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
+ sizeof(rsnxe_buf));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsnxe_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE FT override for MIC calculation");
+ rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
+ rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
+ *elem_count += 1;
+
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kck = sm->PTK.kck2;
kck_len = sm->PTK.kck2_len;
@@ -2596,6 +2775,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
+ rsnxe_len ? rsnxe : NULL, rsnxe_len,
fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return NULL;
@@ -2614,16 +2794,26 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
+}
+
+
+static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (!wpa_auth->cb->add_sta_ft)
+ return -1;
+ return wpa_auth->cb->add_sta_ft(wpa_auth->cb_ctx, addr);
}
-void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry)
{
enum wpa_alg alg;
int klen;
@@ -2645,19 +2835,22 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
return;
}
+ if (!retry)
+ wpa_auth_add_sta_ft(sm->wpa_auth, sm->addr);
+
/* FIX: add STA entry to kernel/driver here? The set_key will fail
* most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called
* again after association to get the PTK configured, but that could be
* optimized by adding the STA entry earlier.
*/
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen))
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
- sm->tk_already_set = TRUE;
+ sm->pairwise_set = true;
+ sm->tk_already_set = true;
}
@@ -2818,8 +3011,6 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
conf->r1_key_holder,
sm->addr, out_pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
os_get_reltime(&now);
if (r0->expiration)
@@ -2875,7 +3066,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *identity, *radius_cui;
size_t identity_len = 0, radius_cui_len = 0;
int use_sha384;
- size_t pmk_r1_len;
+ size_t pmk_r1_len, kdk_len;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -2948,8 +3139,6 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
sm->wpa_auth->conf.r1_key_holder, sm->addr,
pmk_r1_name, use_sha384) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
- pmk_r1_name, WPA_PMK_NAME_LEN);
if (conf->ft_psk_generate_local &&
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -3007,16 +3196,23 @@ pmk_r1_derived:
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, pmk_r1_name,
&sm->PTK, ptk_name, sm->wpa_key_mgmt,
- pairwise) < 0)
+ pairwise, kdk_len) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
- wpa_ft_install_ptk(sm);
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
+ wpa_ft_install_ptk(sm, 0);
if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
@@ -3051,7 +3247,8 @@ pmk_r1_derived:
pos += ret;
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
- sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
+ 0);
if (ret < 0)
goto fail;
pos += ret;
@@ -3110,7 +3307,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
}
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len)
{
struct wpa_ft_ies parse;
@@ -3123,10 +3320,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
int use_sha384;
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int rsnxe_used;
+ struct wpa_auth_config *conf;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ conf = &sm->wpa_auth->conf;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
@@ -3155,8 +3355,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
- os_memcmp(mdie->mobility_domain,
- sm->wpa_auth->conf.mobility_domain,
+ os_memcmp(mdie->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
return WLAN_STATUS_INVALID_MDIE;
@@ -3173,6 +3372,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -3186,6 +3386,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -3231,14 +3432,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
- sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+ conf->r1_key_holder, FT_R1KH_ID_LEN);
return WLAN_STATUS_INVALID_FTIE;
}
@@ -3253,6 +3454,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -3272,6 +3475,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3290,14 +3495,25 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
parse.rsn - 2, parse.rsn_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
return WLAN_STATUS_INVALID_FTIE;
}
+ if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
+ !parse.rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
+ return -1; /* discard request */
+ }
+
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3311,10 +3527,21 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
+ if (sm->wpa_auth->conf.msg_ctx)
+ wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=ft-reassoc-req error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
+ return WLAN_STATUS_INVALID_FTIE;
}
}
#endif /* CONFIG_OCV */
@@ -3537,14 +3764,11 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
};
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 for peer AP");
if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
pmk_r0->pmk_r0_name, r1kh_id,
s1kh_id, pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
- pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
- pmk_r1_name, WPA_PMK_NAME_LEN);
WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
os_get_reltime(&now);
@@ -3674,6 +3898,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
resp[0].type = FT_RRB_S1KH_ID;
resp[0].len = f_s1kh_id_len;
resp[0].data = f_s1kh_id;
@@ -4180,6 +4408,10 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
seq_resp_auth[0].type = FT_RRB_NONCE;
seq_resp_auth[0].len = f_nonce_len;
seq_resp_auth[0].data = f_nonce;
@@ -4409,7 +4641,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
status_code = WPA_GET_LE16(pos);
- pos += 2;
wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
"(status_code=%d)", status_code);
@@ -4422,11 +4653,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
- if (end > pos) {
- wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
- pos, end - pos);
- }
-
return 0;
}
@@ -4439,9 +4665,11 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
size_t alen, elen;
int no_defer = 0;
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
- MACSTR, MAC2STR(src_addr));
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+ ") received frame from remote AP "
+ MACSTR " oui_suffix=%u dst=" MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+ MAC2STR(dst_addr));
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
if (is_multicast_ether_addr(src_addr)) {
@@ -4451,13 +4679,8 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return;
}
- if (is_multicast_ether_addr(dst_addr)) {
- wpa_printf(MSG_DEBUG,
- "FT: RRB-OUI received frame from remote AP " MACSTR
- " to multicast address " MACSTR,
- MAC2STR(src_addr), MAC2STR(dst_addr));
+ if (is_multicast_ether_addr(dst_addr))
no_defer = 1;
- }
if (data_len < sizeof(u16)) {
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4532,6 +4755,10 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
return -1;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
FT_PACKET_R0KH_R1KH_PUSH,
diff --git a/contrib/wpa/src/ap/wpa_auth_glue.c b/contrib/wpa/src/ap/wpa_auth_glue.c
index 0800a874875a..3e992155395e 100644
--- a/contrib/wpa/src/ap/wpa_auth_glue.c
+++ b/contrib/wpa/src/ap/wpa_auth_glue.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/sha1.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
@@ -37,8 +38,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
+ int sae_pw_id;
+
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
+ wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
@@ -64,11 +68,10 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->ocv = conf->ocv;
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
+ wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
@@ -107,9 +110,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->rsn_pairwise = WPA_CIPHER_CCMP;
wconf->rsn_preauth = 0;
wconf->disable_pmksa_caching = 1;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = 1;
-#endif /* CONFIG_IEEE80211W */
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
@@ -122,6 +123,64 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
+ if (conf->rsne_override_eapol &&
+ wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_eapol_set = 1;
+ wconf->rsne_override_eapol_len =
+ wpabuf_len(conf->rsne_override_eapol);
+ os_memcpy(wconf->rsne_override_eapol,
+ wpabuf_head(conf->rsne_override_eapol),
+ wconf->rsne_override_eapol_len);
+ }
+ if (conf->rsnxe_override_eapol &&
+ wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_eapol_set = 1;
+ wconf->rsnxe_override_eapol_len =
+ wpabuf_len(conf->rsnxe_override_eapol);
+ os_memcpy(wconf->rsnxe_override_eapol,
+ wpabuf_head(conf->rsnxe_override_eapol),
+ wconf->rsnxe_override_eapol_len);
+ }
+ if (conf->rsne_override_ft &&
+ wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_ft_set = 1;
+ wconf->rsne_override_ft_len =
+ wpabuf_len(conf->rsne_override_ft);
+ os_memcpy(wconf->rsne_override_ft,
+ wpabuf_head(conf->rsne_override_ft),
+ wconf->rsne_override_ft_len);
+ }
+ if (conf->rsnxe_override_ft &&
+ wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_ft_set = 1;
+ wconf->rsnxe_override_ft_len =
+ wpabuf_len(conf->rsnxe_override_ft);
+ os_memcpy(wconf->rsnxe_override_ft,
+ wpabuf_head(conf->rsnxe_override_ft),
+ wconf->rsnxe_override_ft_len);
+ }
+ if (conf->gtk_rsc_override &&
+ wpabuf_len(conf->gtk_rsc_override) > 0 &&
+ wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->gtk_rsc_override,
+ wpabuf_head(conf->gtk_rsc_override),
+ wpabuf_len(conf->gtk_rsc_override));
+ wconf->gtk_rsc_override_set = 1;
+ }
+ if (conf->igtk_rsc_override &&
+ wpabuf_len(conf->igtk_rsc_override) > 0 &&
+ wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->igtk_rsc_override,
+ wpabuf_head(conf->igtk_rsc_override),
+ wpabuf_len(conf->igtk_rsc_override));
+ wconf->igtk_rsc_override_set = 1;
+ }
+ wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
+ wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3;
+ wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1;
+ wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
+ wconf->oci_freq_override_fils_assoc =
+ conf->oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -134,6 +193,27 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
+ wconf->sae_pwe = conf->sae_pwe;
+ sae_pw_id = hostapd_sae_pw_id_in_use(conf);
+ if (sae_pw_id == 2 && wconf->sae_pwe != 3)
+ wconf->sae_pwe = 1;
+ else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
+ wconf->sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ wconf->sae_pk = hostapd_sae_pk_in_use(conf);
+#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_OWE
+ wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
+ wconf->transition_disable = conf->transition_disable;
+#ifdef CONFIG_DPP2
+ wconf->dpp_pfs = conf->dpp_pfs;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ wconf->force_kdk_derivation = conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
}
@@ -211,16 +291,15 @@ static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
break;
case WPA_EAPOL_keyRun:
if (sta->eapol_sm)
- sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+ sta->eapol_sm->keyRun = value;
break;
case WPA_EAPOL_keyAvailable:
if (sta->eapol_sm)
- sta->eapol_sm->eap_if->eapKeyAvailable =
- value ? TRUE : FALSE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = value;
break;
case WPA_EAPOL_keyDone:
if (sta->eapol_sm)
- sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+ sta->eapol_sm->keyDone = value;
break;
case WPA_EAPOL_inc_EapolFramesTx:
if (sta->eapol_sm)
@@ -357,19 +436,27 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
- size_t key_len)
+ size_t key_len, enum key_flag key_flag)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
- if (ifname == NULL)
- return -1;
+ if (!ifname) {
+ if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
+ return -1;
+ ifname = hapd->conf->iface;
+ }
}
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (key_flag & KEY_FLAG_MODIFY) {
+ /* We are updating an already installed key. Don't overwrite
+ * the already stored key information with zeros.
+ */
+ } else if (addr && !is_broadcast_ether_addr(addr)) {
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
@@ -380,17 +467,23 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = key_len;
}
-#ifdef CONFIG_IEEE80211W
- } else if (alg == WPA_ALG_IGTK ||
+ } else if (alg == WPA_ALG_BIP_CMAC_128 ||
alg == WPA_ALG_BIP_GMAC_128 ||
alg == WPA_ALG_BIP_GMAC_256 ||
alg == WPA_ALG_BIP_CMAC_256) {
- hapd->last_igtk_alg = alg;
- hapd->last_igtk_key_idx = idx;
- if (key)
- os_memcpy(hapd->last_igtk, key, key_len);
- hapd->last_igtk_len = key_len;
-#endif /* CONFIG_IEEE80211W */
+ if (idx == 4 || idx == 5) {
+ hapd->last_igtk_alg = alg;
+ hapd->last_igtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_igtk, key, key_len);
+ hapd->last_igtk_len = key_len;
+ } else if (idx == 6 || idx == 7) {
+ hapd->last_bigtk_alg = alg;
+ hapd->last_bigtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_bigtk, key, key_len);
+ hapd->last_bigtk_len = key_len;
+ }
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -399,8 +492,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
- key, key_len);
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
+ NULL, 0, key, key_len, key_flag);
}
@@ -412,9 +505,9 @@ static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
}
-static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
- const u8 *data, size_t data_len,
- int encrypt)
+int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+ const u8 *data, size_t data_len,
+ int encrypt)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
@@ -620,10 +713,6 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
#endif /* CONFIG_IEEE80211R_AP */
- if (hapd->driver && hapd->driver->send_ether)
- return hapd->driver->send_ether(hapd->drv_priv, dst,
- hapd->own_addr, proto,
- data, data_len);
if (hapd->l2 == NULL)
return -1;
@@ -685,6 +774,12 @@ static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
struct oui_deliver_later_data, list) {
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+ wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ hapd->conf->iface, __func__,
+ MAC2STR(data->src_addr), MAC2STR(data->dst_addr),
+ data->oui_suffix, (unsigned int) data->data_len,
+ data);
if (hapd->wpa_auth && oui_ctx) {
eth_p_oui_deliver(oui_ctx, data->src_addr,
data->dst_addr,
@@ -709,16 +804,26 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_oui_iface_iter_data *idata = ctx;
struct oui_deliver_later_data *data;
- struct hostapd_data *hapd;
+ struct hostapd_data *hapd, *src_hapd = idata->src_hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
- if (hapd == idata->src_hapd)
- continue;
+ if (hapd == src_hapd)
+ continue; /* don't deliver back to same interface */
+ if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) ||
+ hapd->conf->ssid.ssid_len !=
+ src_hapd->conf->ssid.ssid_len ||
+ os_memcmp(hapd->conf->ssid.ssid,
+ src_hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len) != 0 ||
+ os_memcmp(hapd->conf->mobility_domain,
+ src_hapd->conf->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0)
+ continue; /* no matching FT SSID/mobility domain */
if (!is_multicast_ether_addr(idata->dst_addr) &&
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
- continue;
+ continue; /* destination address does not match */
/* defer eth_p_oui_deliver until next eloop step as this is
* when it would be triggerd from reading from sock
@@ -730,14 +835,20 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
data = os_zalloc(sizeof(*data) + idata->data_len);
if (!data)
return 1;
+ wpa_printf(MSG_DEBUG,
+ "RRB(%s): local delivery to %s dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ src_hapd->conf->iface, hapd->conf->iface,
+ MAC2STR(idata->dst_addr), idata->oui_suffix,
+ (unsigned int) idata->data_len, data);
- os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN);
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
os_memcpy(data + 1, idata->data, idata->data_len);
data->data_len = idata->data_len;
data->oui_suffix = idata->oui_suffix;
- dl_list_add(&hapd->l2_oui_queue, &data->list);
+ dl_list_add_tail(&hapd->l2_oui_queue, &data->list);
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
hapd, NULL))
@@ -745,7 +856,11 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
hostapd_oui_deliver_later,
hapd, NULL);
- return 1;
+ /* If dst_addr is a multicast address, do not return any
+ * non-zero value here. Otherwise, the iteration of
+ * for_each_interface() will be stopped. */
+ if (!is_multicast_ether_addr(idata->dst_addr))
+ return 1;
}
return 0;
@@ -761,6 +876,10 @@ static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
struct hostapd_data *hapd = ctx;
struct eth_p_oui_ctx *oui_ctx;
+ wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR
+ " oui_suffix=%u data_len=%u",
+ hapd->conf->iface, MAC2STR(dst), oui_suffix,
+ (unsigned int) data_len);
#ifdef CONFIG_IEEE80211R_AP
if (hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@@ -799,31 +918,58 @@ static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
}
+#ifdef CONFIG_PASN
+
+static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
+}
+
+
+static void hostapd_clear_ptksa(void *ctx, const u8 *addr, int cipher)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_flush(hapd->ptksa, addr, cipher);
+}
+
+#endif /* CONFIG_PASN */
+
+
static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
{
#ifndef CONFIG_NO_VLAN
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
- struct vlan_description vlan_desc;
sta = ap_get_sta(hapd, addr);
if (!sta)
return -1;
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
- vlan_desc.notempty = 1;
- vlan_desc.untagged = vlan_id;
- if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
- vlan_id);
- return -1;
- }
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ struct vlan_description vlan_desc;
- if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
- wpa_printf(MSG_INFO,
- "Failed to assign VLAN ID %d from wpa_psk_file to "
- MACSTR, vlan_id, MAC2STR(sta->addr));
- return -1;
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO,
+ "Invalid VLAN ID %d in wpa_psk_file",
+ vlan_id);
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from wpa_psk_file to "
+ MACSTR, vlan_id, MAC2STR(sta->addr));
+ return -1;
+ }
+ } else {
+ sta->vlan_id = vlan_id;
}
wpa_printf(MSG_INFO,
@@ -885,7 +1031,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
- res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0);
os_free(m);
return res;
}
@@ -896,18 +1042,28 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int ret;
wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
" based on WPA authenticator callback",
MAC2STR(sta_addr));
- if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ ret = hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT);
+
+ /*
+ * The expected return values from hostapd_add_sta_node() are
+ * 0: successfully added STA entry
+ * -EOPNOTSUPP: driver or driver wrapper does not support/need this
+ * operations
+ * any other negative value: error in adding the STA entry */
+ if (ret < 0 && ret != -EOPNOTSUPP)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
- if (hapd->driver && hapd->driver->add_sta_node)
+ if (ret == 0)
sta->added_unassoc = 1;
+
sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
@@ -925,6 +1081,34 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
}
+static int hostapd_wpa_auth_add_sta_ft(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (sta->flags & WLAN_STA_MFP) && ap_sta_is_authorized(sta) &&
+ !(hapd->conf->mesh & MESH_ENABLED) && !(sta->added_unassoc)) {
+ /* We could not do this in handle_auth() since there was a
+ * PMF-enabled association for the STA and the new
+ * authentication attempt was not yet fully processed. Now that
+ * we are ready to configure the TK to the driver,
+ * authentication has succeeded and we can clean up the driver
+ * STA entry to avoid issues with any maintained state from the
+ * previous association. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Remove and re-add driver STA entry after successful FT authentication");
+ return ap_sta_re_add(hapd, sta);
+ }
+
+ return 0;
+}
+
+
static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan)
{
@@ -1280,12 +1464,18 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
.send_oui = hostapd_wpa_auth_send_oui,
.channel_info = hostapd_channel_info,
.update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_PASN
+ .store_ptksa = hostapd_store_ptksa,
+ .clear_ptksa = hostapd_clear_ptksa,
+#endif /* CONFIG_PASN */
+
#ifdef CONFIG_OCV
.get_sta_tx_params = hostapd_get_sta_tx_params,
#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta,
+ .add_sta_ft = hostapd_wpa_auth_add_sta_ft,
.add_tspec = hostapd_wpa_auth_add_tspec,
.set_vlan = hostapd_wpa_auth_set_vlan,
.get_vlan = hostapd_wpa_auth_get_vlan,
@@ -1301,10 +1491,43 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
+ _conf.msg_ctx = hapd->msg_ctx;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with disconnect");
+ _conf.wpa_deny_ptk0_rekey = 1;
+ }
+
+ if (_conf.extended_key_id &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
+ else
+ _conf.extended_key_id = 0;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ _conf.beacon_prot = 0;
+
+#ifdef CONFIG_OCV
+ if (!(hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
+ _conf.ocv = 0;
+#endif /* CONFIG_OCV */
+
+ _conf.secure_ltf =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
+ _conf.secure_rtt =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
+ _conf.prot_range_neg =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1330,6 +1553,13 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
return -1;
}
+ if (!hapd->ptksa)
+ hapd->ptksa = ptksa_cache_init();
+ if (!hapd->ptksa) {
+ wpa_printf(MSG_ERROR, "Failed to allocate PTKSA cache");
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R_AP
if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
@@ -1339,9 +1569,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
hapd->conf->iface;
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
- if (hapd->l2 == NULL &&
- (hapd->driver == NULL ||
- hapd->driver->send_ether == NULL)) {
+ if (!hapd->l2) {
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
"interface");
return -1;
@@ -1371,6 +1599,9 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
ieee80211_tkip_countermeasures_deinit(hapd);
+ ptksa_cache_deinit(hapd->ptksa);
+ hapd->ptksa = NULL;
+
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
diff --git a/contrib/wpa/src/ap/wpa_auth_i.h b/contrib/wpa/src/ap/wpa_auth_i.h
index 4babd0cbb044..a6dc1a59185d 100644
--- a/contrib/wpa/src/ap/wpa_auth_i.h
+++ b/contrib/wpa/src/ap/wpa_auth_i.h
@@ -39,20 +39,20 @@ struct wpa_state_machine {
WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state;
- Boolean Init;
- Boolean DeauthenticationRequest;
- Boolean AuthenticationRequest;
- Boolean ReAuthenticationRequest;
- Boolean Disconnect;
+ bool Init;
+ bool DeauthenticationRequest;
+ bool AuthenticationRequest;
+ bool ReAuthenticationRequest;
+ bool Disconnect;
u16 disconnect_reason; /* specific reason code to use with Disconnect */
u32 TimeoutCtr;
u32 GTimeoutCtr;
- Boolean TimeoutEvt;
- Boolean EAPOLKeyReceived;
- Boolean EAPOLKeyPairwise;
- Boolean EAPOLKeyRequest;
- Boolean MICVerified;
- Boolean GUpdateStationKeys;
+ bool TimeoutEvt;
+ bool EAPOLKeyReceived;
+ bool EAPOLKeyPairwise;
+ bool EAPOLKeyRequest;
+ bool MICVerified;
+ bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
@@ -61,20 +61,22 @@ struct wpa_state_machine {
unsigned int pmk_len;
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
- Boolean PTK_valid;
- Boolean pairwise_set;
- Boolean tk_already_set;
+ u8 keyidx_active;
+ bool use_ext_key_id;
+ bool PTK_valid;
+ bool pairwise_set;
+ bool tk_already_set;
int keycount;
- Boolean Pair;
+ bool Pair;
struct wpa_key_replay_counter {
u8 counter[WPA_REPLAY_COUNTER_LEN];
- Boolean valid;
+ bool valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES],
prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
- Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
- Boolean PTKRequest; /* not in IEEE 802.11i state machine */
- Boolean has_GTK;
- Boolean PtkGroupInit; /* init request for PTK Group state machine */
+ bool PInitAKeys; /* WPA only, not in IEEE 802.11i */
+ bool PTKRequest; /* not in IEEE 802.11i state machine */
+ bool has_GTK;
+ bool PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len;
@@ -93,8 +95,9 @@ struct wpa_state_machine {
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+
#ifdef CONFIG_OCV
- unsigned int ocv_enabled:1;
+ int ocv_enabled;
#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
@@ -102,6 +105,8 @@ struct wpa_state_machine {
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsnxe;
+ size_t rsnxe_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -170,12 +175,12 @@ struct wpa_group {
struct wpa_group *next;
int vlan_id;
- Boolean GInit;
+ bool GInit;
int GKeyDoneStations;
- Boolean GTKReKey;
+ bool GTKReKey;
int GTK_len;
int GN, GM;
- Boolean GTKAuthenticator;
+ bool GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN];
enum {
@@ -187,13 +192,13 @@ struct wpa_group {
u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
- Boolean changed;
- Boolean first_sta_seen;
- Boolean reject_4way_hs_for_entropy;
-#ifdef CONFIG_IEEE80211W
+ bool changed;
+ bool first_sta_seen;
+ bool reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN];
+ u8 BIGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
-#endif /* CONFIG_IEEE80211W */
+ int GN_bigtk, GM_bigtk;
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -269,10 +274,12 @@ struct ft_remote_seq {
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
- logger_level level, const char *fmt, ...);
+ logger_level level, const char *fmt, ...)
+ PRINTF_FORMAT(4, 5);
void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int key_info,
const u8 *key_rsc, const u8 *nonce,
@@ -291,11 +298,11 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len);
+ size_t subelem_len, int rsnxe_used);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
-void wpa_ft_install_ptk(struct wpa_state_machine *sm);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.c b/contrib/wpa/src/ap/wpa_auth_ie.c
index 2e5c9160d18f..524922e4e686 100644
--- a/contrib/wpa/src/ap/wpa_auth_ie.c
+++ b/contrib/wpa/src/ap/wpa_auth_ie.c
@@ -88,13 +88,42 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
+static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
+{
+ u16 capab = 0;
+
+ if (conf->rsn_preauth)
+ capab |= WPA_CAPABILITY_PREAUTH;
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_RSN_TESTING
+ if (rsn_testing)
+ capab |= BIT(8) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
int num_suites, res;
u8 *pos, *count;
- u16 capab;
u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
@@ -183,7 +212,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
@@ -194,7 +222,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -262,6 +289,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_PASN */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -279,29 +313,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
- capab = 0;
- if (conf->rsn_preauth)
- capab |= WPA_CAPABILITY_PREAUTH;
- if (conf->wmm_enabled) {
- /* 4 PTKSA replay counters when using WMM */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
- }
-#ifdef CONFIG_IEEE80211W
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- capab |= WPA_CAPABILITY_MFPC;
- if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
- capab |= WPA_CAPABILITY_MFPR;
- }
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_OCV
- if (conf->ocv)
- capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
-#ifdef CONFIG_RSN_TESTING
- if (rsn_testing)
- capab |= BIT(8) | BIT(15);
-#endif /* CONFIG_RSN_TESTING */
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
pos += 2;
if (pmkid) {
@@ -314,7 +326,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
@@ -347,7 +358,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -378,6 +388,46 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+ u16 capab = 0;
+ size_t flen;
+
+ if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (conf->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (conf->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (conf->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (conf->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ if (len < 2 + flen)
+ return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
+
+ return pos - buf;
+}
+
+
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
@@ -411,13 +461,11 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -464,6 +512,11 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
if (res < 0)
return res;
pos += res;
+ res = wpa_write_rsnxe(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
@@ -529,12 +582,15 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
}
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int freq,
- const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len)
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
@@ -607,12 +663,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
@@ -717,12 +771,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
@@ -758,7 +810,6 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_INVALID_PAIRWISE;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
@@ -786,14 +837,26 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_SAE */
#ifdef CONFIG_OCV
- if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
- wpa_printf(MSG_DEBUG,
- "Management frame protection required with OCV, but client did not enable it");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
+ * AP RSN capabilities. To improve interoperability with such
+ * legacy STAs allow connection without enabling OCV when the
+ * workaround mode (ocv=2) is enabled.
+ */
+ if (wpa_auth->conf.ocv == 2) {
+ wpa_printf(MSG_DEBUG,
+ "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
+ wpa_auth_set_ocv(sm, 0);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ } else {
+ wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
+ wpa_auth->conf.ocv : 0);
}
- wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
- (data.capabilities & WPA_CAPABILITY_OCVC));
#endif /* CONFIG_OCV */
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
@@ -807,7 +870,6 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
"Management frame protection cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -835,19 +897,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
"OWE: No Diffie-Hellman Parameter element");
return WPA_INVALID_AKMP;
}
-#ifdef CONFIG_DPP
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
- /* Diffie-Hellman Parameter element can be used with DPP as
- * well, so allow this to proceed. */
- } else
-#endif /* CONFIG_DPP */
- if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
- wpa_printf(MSG_DEBUG,
- "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
- return WPA_INVALID_AKMP;
- }
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ ((conf->dpp_pfs == 1 && !owe_dh) ||
+ (conf->dpp_pfs == 2 && owe_dh))) {
+ wpa_printf(MSG_DEBUG, "DPP: PFS %s",
+ conf->dpp_pfs == 1 ? "required" : "not allowed");
+ return WPA_DENIED_OTHER_REASON;
+ }
+#endif /* CONFIG_DPP2 */
+
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE;
@@ -932,6 +993,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_DPP */
+ if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+ sm->pairwise != WPA_CIPHER_TKIP &&
+ (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+ sm->use_ext_key_id = true;
+ if (conf->extended_key_id == 2 &&
+ !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ sm->keyidx_active = 1;
+ else
+ sm->keyidx_active = 0;
+ wpa_printf(MSG_DEBUG,
+ "RSN: Extended Key ID supported (start with %d)",
+ sm->keyidx_active);
+ } else {
+ sm->use_ext_key_id = false;
+ }
+
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
@@ -941,6 +1019,21 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
+ if (rsnxe && rsnxe_len) {
+ if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) {
+ os_free(sm->rsnxe);
+ sm->rsnxe = os_malloc(rsnxe_len);
+ if (!sm->rsnxe)
+ return WPA_ALLOC_FAIL;
+ }
+ os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
+ sm->rsnxe_len = rsnxe_len;
+ } else {
+ os_free(sm->rsnxe);
+ sm->rsnxe = NULL;
+ sm->rsnxe_len = 0;
+ }
+
return WPA_IE_OK;
}
@@ -975,153 +1068,6 @@ int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_HS20 */
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- return 0;
- }
-
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
- ie->osen = pos;
- ie->osen_len = pos[1] + 2;
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
-
-
-/**
- * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R_AP
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R_AP */
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
-}
-
-
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
@@ -1179,6 +1125,7 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
#ifdef CONFIG_FILS
+
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
@@ -1195,4 +1142,91 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
return pos;
return pos + res;
}
+
+
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info)
+{
+ struct wpa_auth_config *conf;
+ u32 selectors = 0;
+ u8 *pos = fd_rsn_info;
+ int i, res;
+ u32 cipher, suite, selector, mask;
+ u8 tmp[10 * RSN_SELECTOR_LEN];
+
+ if (!wpa_auth)
+ return false;
+ conf = &wpa_auth->conf;
+
+ if (!(conf->wpa & WPA_PROTO_RSN))
+ return false;
+
+ /* RSN Capability (B0..B15) */
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+ pos += 2;
+
+ /* Group Data Cipher Suite Selector (B16..B21) */
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+ cipher = 63; /* No cipher suite selected */
+ else if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
+ cipher = suite & 0xff;
+ else
+ cipher = 62; /* vendor specific */
+ selectors |= cipher;
+
+ /* Group Management Cipher Suite Selector (B22..B27) */
+ cipher = 63; /* Default to no cipher suite selected */
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ switch (conf->group_mgmt_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
+ cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
+ break;
+ }
+ }
+ selectors |= cipher << 6;
+
+ /* Pairwise Cipher Suite Selector (B28..B33) */
+ cipher = 63; /* Default to no cipher suite selected */
+ res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
+ if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
+ tmp[3] <= 13)
+ cipher = tmp[3];
+ selectors |= cipher << 12;
+
+ /* AKM Suite Selector (B34..B39) */
+ selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
+ mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA384;
+ if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
+ suite = conf->wpa_key_mgmt & mask;
+ if (suite == WPA_KEY_MGMT_FILS_SHA256)
+ selector = 1; /* 00-0f-ac:14 */
+ else if (suite == WPA_KEY_MGMT_FILS_SHA384)
+ selector = 2; /* 00-0f-ac:15 */
+ else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384))
+ selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
+ else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
+ selector = 4; /* 00-0f-ac:17 */
+ }
+ selectors |= selector << 18;
+
+ for (i = 0; i < 3; i++) {
+ *pos++ = selectors & 0xff;
+ selectors >>= 8;
+ }
+
+ return true;
+}
+
#endif /* CONFIG_FILS */
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.h b/contrib/wpa/src/ap/wpa_auth_ie.h
index a38b206fd0f4..dd44b9efe2c6 100644
--- a/contrib/wpa/src/ap/wpa_auth_ie.h
+++ b/contrib/wpa/src/ap/wpa_auth_ie.h
@@ -9,41 +9,6 @@
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R_AP
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-
- const u8 *osen;
- size_t osen_len;
-};
-
-int wpa_parse_kde_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
diff --git a/contrib/wpa/src/ap/wpa_auth_kay.c b/contrib/wpa/src/ap/wpa_auth_kay.c
index b6e47979bea8..46d94b43f83e 100644
--- a/contrib/wpa/src/ap/wpa_auth_kay.c
+++ b/contrib/wpa/src/ap/wpa_auth_kay.c
@@ -52,7 +52,7 @@ static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
}
-static int hapd_enable_protect_frames(void *priv, Boolean enabled)
+static int hapd_enable_protect_frames(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -62,7 +62,7 @@ static int hapd_enable_protect_frames(void *priv, Boolean enabled)
}
-static int hapd_enable_encrypt(void *priv, Boolean enabled)
+static int hapd_enable_encrypt(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -72,7 +72,7 @@ static int hapd_enable_encrypt(void *priv, Boolean enabled)
}
-static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
+static int hapd_set_replay_protect(void *priv, bool enabled, u32 window)
{
struct hostapd_data *hapd = priv;
@@ -93,7 +93,7 @@ static int hapd_set_current_cipher_suite(void *priv, u64 cs)
}
-static int hapd_enable_controlled_port(void *priv, Boolean enabled)
+static int hapd_enable_controlled_port(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -465,7 +465,7 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
- TRUE);
+ true);
fail:
bin_clear_free(msk, sizeof(*msk));
@@ -507,7 +507,7 @@ void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
ckn->len = hapd->conf->mka_ckn_len;;
os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
- res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
if (res)
goto free_cak;
diff --git a/contrib/wpa/src/ap/wps_hostapd.c b/contrib/wpa/src/ap/wps_hostapd.c
index 6161cdbdb922..9f22e39a2e6a 100644
--- a/contrib/wpa/src/ap/wps_hostapd.c
+++ b/contrib/wpa/src/ap/wps_hostapd.c
@@ -125,6 +125,7 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
os_memcpy(p->addr, mac_addr, ETH_ALEN);
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
+ p->wps = 1;
if (hapd->new_psk_cb) {
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
@@ -137,16 +138,17 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
if (ssid->wpa_psk_file) {
FILE *f;
char hex[PMK_LEN * 2 + 1];
+
/* Add the new PSK to PSK list file */
f = fopen(ssid->wpa_psk_file, "a");
- if (f == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
- "'%s'", ssid->wpa_psk_file);
+ if (!f) {
+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'",
+ ssid->wpa_psk_file);
return -1;
}
wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
- fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+ fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex);
fclose(f);
}
@@ -269,6 +271,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
}
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+ const u8 **psk)
+{
+ const struct hostapd_data *hapd = ctx;
+ const struct hostapd_wpa_psk *wpa_psk;
+ const u8 *any_psk = NULL;
+ const u8 *dev_psk = NULL;
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk;
+ wpa_psk = wpa_psk->next) {
+ if (!wpa_psk->wps)
+ continue;
+
+ if (!any_psk && is_zero_ether_addr(wpa_psk->addr))
+ any_psk = wpa_psk->psk;
+
+ if (mac_addr && !dev_psk &&
+ os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+ dev_psk = wpa_psk->psk;
+ break;
+ }
+ }
+
+ if (dev_psk) {
+ *psk = dev_psk;
+ } else if (any_psk) {
+ *psk = any_psk;
+ } else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: No appropriate PSK in wpa_psk_file");
+ return 0;
+ }
+
+ return 1;
+}
+
+
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
@@ -324,6 +364,13 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->ssid.ssid_set = 1;
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 2;
+ else
+ bss->wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
bss->wpa = 3;
@@ -333,6 +380,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa = 1;
else
bss->wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (bss->wpa) {
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
@@ -347,8 +395,10 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
else
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = bss->wpa_pairwise;
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
bss->wpa_pairwise,
@@ -358,12 +408,10 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
bss->ieee80211w =
MGMT_FRAME_PROTECTION_OPTIONAL;
bss->sae_require_mfp = 1;
-#endif /* CONFIG_IEEE80211W */
}
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -521,6 +569,13 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "\n");
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ wpa = 2;
+ else
+ wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
wpa = 3;
@@ -530,12 +585,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
wpa = 1;
else
wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (wpa) {
char *prefix;
-#ifdef CONFIG_IEEE80211W
int sae = 0;
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa=%d\n", wpa);
@@ -553,13 +607,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
cred->key_len != 2 * PMK_LEN) {
fprintf(nconf, "%sSAE", prefix);
-#ifdef CONFIG_IEEE80211W
sae = 1;
-#endif /* CONFIG_IEEE80211W */
}
fprintf(nconf, "\n");
-#ifdef CONFIG_IEEE80211W
if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
fprintf(nconf, "ieee80211w=%d\n",
MGMT_FRAME_PROTECTION_OPTIONAL);
@@ -567,7 +618,6 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
}
if (sae)
fprintf(nconf, "sae_require_mfp=1\n");
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa_pairwise=");
prefix = "";
@@ -579,9 +629,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
prefix = " ";
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP) {
fprintf(nconf, "%sTKIP", prefix);
}
+#endif /* CONFIG_NO_TKIP */
fprintf(nconf, "\n");
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -619,8 +671,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
(str_starts(buf, "ssid=") ||
str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
+#ifdef CONFIG_WEP
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
+#endif /* CONFIG_WEP */
str_starts(buf, "wps_state=") ||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
@@ -993,6 +1047,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
}
+static int hostapd_wps_set_application_ext(struct hostapd_data *hapd,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.application_ext);
+
+ if (!hapd->conf->wps_application_ext) {
+ wps->dev.application_ext = NULL;
+ return 0;
+ }
+
+ wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext);
+ return wps->dev.application_ext ? 0 : -1;
+}
+
+
static void hostapd_free_wps(struct wps_context *wps)
{
int i;
@@ -1082,7 +1151,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
WPS_DEV_TYPE_LEN);
- if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 ||
+ hostapd_wps_set_application_ext(hapd, wps) < 0)
goto fail;
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -1102,6 +1172,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->auth_types |= WPS_AUTH_WPA2PSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA2;
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE)
+ wps->auth_types |= WPS_AUTH_WPA2PSK;
if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 |
@@ -1110,12 +1182,24 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->encr_types_rsn |= WPS_ENCR_AES;
}
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+#ifdef CONFIG_NO_TKIP
+ wpa_printf(MSG_INFO, "WPS: TKIP not supported");
+ goto fail;
+#else /* CONFIG_NO_TKIP */
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_rsn |= WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
}
if (conf->wpa & WPA_PROTO_WPA) {
+#ifdef CONFIG_NO_TKIP
+ if (!(conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_INFO, "WPS: WPA(v1) not supported");
+ goto fail;
+ }
+ conf->wpa &= ~WPA_PROTO_WPA;
+#else /* CONFIG_NO_TKIP */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPAPSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
@@ -1129,6 +1213,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_wpa |= WPS_ENCR_TKIP;
}
+#endif /* CONFIG_NO_TKIP */
}
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
@@ -1148,6 +1233,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL)
@@ -1155,6 +1241,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
}
if (conf->ssid.wpa_psk) {
@@ -1166,10 +1253,17 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->ap_encr_type = wps->encr_types;
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+ wps->encr_types_rsn = WPS_ENCR_AES;
+ wps->encr_types_wpa = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
@@ -1205,14 +1299,13 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+ cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
- if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
- cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
(WPS_RF_50GHZ | WPS_RF_24GHZ))
@@ -1237,6 +1330,11 @@ int hostapd_init_wps(struct hostapd_data *hapd,
hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
+#ifdef CONFIG_P2P
+ if ((hapd->conf->p2p & P2P_ENABLED) &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ wps->use_passphrase = true;
+#endif /* CONFIG_P2P */
hapd->wps = wps;
bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
@@ -1285,6 +1383,48 @@ static void hostapd_wps_nfc_clear(struct wps_context *wps)
}
+static int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
+ struct wps_registrar *reg)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 *multi_ap_backhaul_network_key = NULL;
+ size_t multi_ap_backhaul_network_key_len = 0;
+ int ret;
+
+ if (!(conf->multi_ap & FRONTHAUL_BSS) ||
+ !conf->multi_ap_backhaul_ssid.ssid_len)
+ return 0;
+
+ if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+ multi_ap_backhaul_network_key =
+ (u8 *) os_strdup(
+ conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ multi_ap_backhaul_network_key_len =
+ os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ } else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+ multi_ap_backhaul_network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ wpa_snprintf_hex((char *) multi_ap_backhaul_network_key,
+ 2 * PMK_LEN + 1,
+ conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN);
+ multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+ }
+
+ ret = wps_registrar_update_multi_ap(
+ reg, conf->multi_ap_backhaul_ssid.ssid,
+ conf->multi_ap_backhaul_ssid.ssid_len,
+ multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ os_free(multi_ap_backhaul_network_key);
+
+ return ret;
+}
+
+
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1307,21 +1447,65 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
void hostapd_update_wps(struct hostapd_data *hapd)
{
- if (hapd->wps == NULL)
+ struct wps_context *wps = hapd->wps;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!wps)
return;
#ifdef CONFIG_WPS_UPNP
- hapd->wps->friendly_name = hapd->conf->friendly_name;
- hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
- hapd->wps->model_description = hapd->conf->model_description;
- hapd->wps->model_url = hapd->conf->model_url;
- hapd->wps->upc = hapd->conf->upc;
+ wps->friendly_name = conf->friendly_name;
+ wps->manufacturer_url = conf->manufacturer_url;
+ wps->model_description = conf->model_description;
+ wps->model_url = conf->model_url;
+ wps->upc = conf->upc;
#endif /* CONFIG_WPS_UPNP */
- hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+ os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len);
+ wps->ssid_len = conf->ssid.ssid_len;
- if (hapd->conf->wps_state)
- wps_registrar_update_ie(hapd->wps->registrar);
+ /* Clear WPS settings, then fill them again */
+ os_free(wps->network_key);
+ wps->network_key = NULL;
+ wps->network_key_len = 0;
+ wps->psk_set = 0;
+ if (conf->ssid.wpa_psk_file) {
+ /* Use per-device PSKs */
+ } else if (conf->ssid.wpa_passphrase) {
+ wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+ if (!wps->network_key)
+ return;
+ wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+ } else if (conf->ssid.wpa_psk) {
+ wps->network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!wps->network_key)
+ return;
+ wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+ conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
+ } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+ wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+ if (!wps->network_key)
+ return;
+ os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+ conf->ssid.wep.len[0]);
+ wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
+ }
+
+ if (conf->ssid.wpa_psk) {
+ os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->psk_set = 1;
+ }
+
+ hostapd_wps_update_multi_ap(hapd, wps->registrar);
+
+ hostapd_wps_set_vendor_ext(hapd, wps);
+ hostapd_wps_set_application_ext(hapd, wps);
+
+ if (conf->wps_state)
+ wps_registrar_update_ie(wps->registrar);
else
hostapd_deinit_wps(hapd);
}
@@ -1425,6 +1609,7 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
data->count++;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_CANCEL);
}
return 0;
@@ -1748,8 +1933,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (os_strncmp(auth, "OPEN", 4) == 0)
cred.auth_type = WPS_AUTH_OPEN;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(auth, "WPAPSK", 6) == 0)
cred.auth_type = WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
cred.auth_type = WPS_AUTH_WPA2PSK;
else
@@ -1758,8 +1945,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (encr) {
if (os_strncmp(encr, "NONE", 4) == 0)
cred.encr_type = WPS_ENCR_NONE;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(encr, "TKIP", 4) == 0)
cred.encr_type = WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(encr, "CCMP", 4) == 0)
cred.encr_type = WPS_ENCR_AES;
else
diff --git a/contrib/wpa/src/build.rules b/contrib/wpa/src/build.rules
new file mode 100644
index 000000000000..acda8847284d
--- /dev/null
+++ b/contrib/wpa/src/build.rules
@@ -0,0 +1,109 @@
+.PHONY: all
+all: _all
+
+# disable built-in rules
+.SUFFIXES:
+
+# setup some variables
+ROOTDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+ROOTDIR := $(dir $(ROOTDIR:%../src/=%))../
+BUILDDIR ?= $(abspath $(ROOTDIR)build)
+BUILDDIR := $(BUILDDIR:%/=%)
+ABSROOT := $(abspath $(ROOTDIR))
+ifeq ($(origin OUT),command line)
+_PROJ := $(OUT:%/=%)
+_PROJ := $(_PROJ:$(BUILDDIR)/%=%)
+else
+_PROJ := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
+_PROJ := $(_PROJ:$(ABSROOT)/%=%)
+endif
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+ifneq ($(CONFIG_FILE),)
+-include $(CONFIG_FILE)
+
+# export for sub-makefiles
+export CONFIG_CODE_COVERAGE
+
+.PHONY: verify_config
+verify_config:
+ @if [ ! -r $(CONFIG_FILE) ]; then \
+ echo 'Building $(firstword $(ALL)) requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+VERIFY := verify_config
+else
+VERIFY :=
+endif
+
+# default target
+.PHONY: _all
+_all: $(VERIFY) $(ALL) $(EXTRA_TARGETS)
+
+# continue setup
+COVSUFFIX := $(if $(CONFIG_CODE_COVERAGE),-cov,)
+PROJ := $(_PROJ)$(COVSUFFIX)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
+
+ifeq ($(Q),@)
+MAKEFLAGS += --no-print-directory
+endif
+
+_DIRS := $(BUILDDIR)/$(PROJ)
+.PHONY: _make_dirs
+_make_dirs:
+ @mkdir -p $(_DIRS)
+
+$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+# for the fuzzing tests
+$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+# libraries - they know how to build themselves
+# (lib_phony so we recurse all the time)
+.PHONY: lib_phony
+lib_phony:
+# nothing
+
+$(BUILDDIR)/$(PROJ)/%.a: $(CONFIG_FILE) lib_phony
+ $(Q)$(MAKE) -C $(ROOTDIR)$(dir $(@:$(BUILDDIR)/$(PROJ)/%=%)) OUT=$(abspath $(dir $@))/
+
+BUILDOBJ = $(patsubst %,$(BUILDDIR)/$(PROJ)/%,$(patsubst $(ROOTDIR)%,%,$(1)))
+
+.PHONY: common-clean
+common-clean:
+ $(Q)rm -rf $(ALL) $(BUILDDIR)/$(PROJ)
diff --git a/contrib/wpa/src/common/Makefile b/contrib/wpa/src/common/Makefile
new file mode 100644
index 000000000000..e2c5f03c2c3b
--- /dev/null
+++ b/contrib/wpa/src/common/Makefile
@@ -0,0 +1,16 @@
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_SAE
+CFLAGS += -DCONFIG_SUITE
+CFLAGS += -DCONFIG_SUITEB
+CFLAGS += -DCONFIG_PTKSA_CACHE
+
+LIB_OBJS= \
+ gas.o \
+ hw_features_common.o \
+ ieee802_11_common.o \
+ sae.o \
+ ptksa_cache.o \
+ wpa_common.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/common/brcm_vendor.h b/contrib/wpa/src/common/brcm_vendor.h
new file mode 100644
index 000000000000..f163dea73768
--- /dev/null
+++ b/contrib/wpa/src/common/brcm_vendor.h
@@ -0,0 +1,156 @@
+/*
+ * Broadcom Corporation OUI and vendor specific assignments
+ * Copyright (c) 2020, Broadcom Corporation.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BRCM_VENDOR_H
+#define BRCM_VENDOR_H
+
+/*
+ * This file is a registry of identifier assignments from the Broadcom
+ * OUI 00:10:18 for purposes other than MAC address assignment. New identifiers
+ * can be assigned through normal review process for changes to the upstream
+ * hostap.git repository.
+ */
+
+#define OUI_BRCM 0x001018
+
+/**
+ * enum brcm_nl80211_vendor_subcmds - BRCM nl80211 vendor command identifiers
+ *
+ * @BRCM_VENDOR_SCMD_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_SCMD_PRIV_STR: Provide vendor private cmds to send to FW.
+ *
+ * @BRCM_VENDOR_SCMD_BCM_STR: Provide vendor cmds to BCMDHD driver.
+ *
+ * @BRCM_VENDOR_SCMD_BCM_PSK: Used to set SAE password.
+ *
+ * @BRCM_VENDOR_SCMD_SET_PMK: Command to check driver support
+ * for DFS offloading.
+ *
+ * @BRCM_VENDOR_SCMD_GET_FEATURES: Command to get the features
+ * supported by the driver.
+ *
+ * @BRCM_VENDOR_SCMD_SET_MAC: Set random mac address for P2P interface.
+ *
+ * @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters.
+ * Used for the case that FW handle SAE.
+ *
+ * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters.
+ * Used for the case that FW handle SAE.
+ *
+ * @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to
+ * invoke the ACS function in device and pass selected channels to
+ * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
+ *
+ * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
+ * Make sure it located at the end of the list.
+ *
+ */
+enum brcm_nl80211_vendor_subcmds {
+ BRCM_VENDOR_SCMD_UNSPEC = 0,
+ BRCM_VENDOR_SCMD_PRIV_STR = 1,
+ BRCM_VENDOR_SCMD_BCM_STR = 2,
+ BRCM_VENDOR_SCMD_BCM_PSK = 3,
+ BRCM_VENDOR_SCMD_SET_PMK = 4,
+ BRCM_VENDOR_SCMD_GET_FEATURES = 5,
+ BRCM_VENDOR_SCMD_SET_MAC = 6,
+ BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS = 7,
+ BRCM_VENDOR_SCMD_SET_START_AP_PARAMS = 8,
+ BRCM_VENDOR_SCMD_ACS = 9,
+ BRCM_VENDOR_SCMD_MAX = 10
+};
+
+/**
+ * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
+ *
+ * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_EVENT_PRIV_STR: String command/event
+ */
+enum brcm_nl80211_vendor_events {
+ BRCM_VENDOR_EVENT_UNSPEC = 0,
+ BRCM_VENDOR_EVENT_PRIV_STR = 1,
+ GOOGLE_GSCAN_SIGNIFICANT_EVENT = 2,
+ GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT = 3,
+ GOOGLE_GSCAN_BATCH_SCAN_EVENT = 4,
+ GOOGLE_SCAN_FULL_RESULTS_EVENT = 5,
+ GOOGLE_RTT_COMPLETE_EVENT = 6,
+ GOOGLE_SCAN_COMPLETE_EVENT = 7,
+ GOOGLE_GSCAN_GEOFENCE_LOST_EVENT = 8,
+ GOOGLE_SCAN_EPNO_EVENT = 9,
+ GOOGLE_DEBUG_RING_EVENT = 10,
+ GOOGLE_FW_DUMP_EVENT = 11,
+ GOOGLE_PNO_HOTSPOT_FOUND_EVENT = 12,
+ GOOGLE_RSSI_MONITOR_EVENT = 13,
+ GOOGLE_MKEEP_ALIVE_EVENT = 14,
+
+ /*
+ * BRCM specific events should be placed after
+ * the Generic events so that enums don't mismatch
+ * between the DHD and HAL
+ */
+ GOOGLE_NAN_EVENT_ENABLED = 15,
+ GOOGLE_NAN_EVENT_DISABLED = 16,
+ GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH = 17,
+ GOOGLE_NAN_EVENT_REPLIED = 18,
+ GOOGLE_NAN_EVENT_PUBLISH_TERMINATED = 19,
+ GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED = 20,
+ GOOGLE_NAN_EVENT_DE_EVENT = 21,
+ GOOGLE_NAN_EVENT_FOLLOWUP = 22,
+ GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND = 23,
+ GOOGLE_NAN_EVENT_DATA_REQUEST = 24,
+ GOOGLE_NAN_EVENT_DATA_CONFIRMATION = 25,
+ GOOGLE_NAN_EVENT_DATA_END = 26,
+ GOOGLE_NAN_EVENT_BEACON = 27,
+ GOOGLE_NAN_EVENT_SDF = 28,
+ GOOGLE_NAN_EVENT_TCA = 29,
+ GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH = 30,
+ GOOGLE_NAN_EVENT_UNKNOWN = 31,
+ GOOGLE_ROAM_EVENT_START = 32,
+ BRCM_VENDOR_EVENT_HANGED = 33,
+ BRCM_VENDOR_EVENT_SAE_KEY = 34,
+ BRCM_VENDOR_EVENT_BEACON_RECV = 35,
+ BRCM_VENDOR_EVENT_PORT_AUTHORIZED = 36,
+ GOOGLE_FILE_DUMP_EVENT = 37,
+ BRCM_VENDOR_EVENT_CU = 38,
+ BRCM_VENDOR_EVENT_WIPS = 39,
+ NAN_ASYNC_RESPONSE_DISABLED = 40,
+ BRCM_VENDOR_EVENT_RCC_INFO = 41,
+ BRCM_VENDOR_EVENT_ACS = 42,
+ BRCM_VENDOR_EVENT_LAST
+
+};
+
+#ifdef CONFIG_BRCM_SAE
+enum wifi_sae_key_attr {
+ BRCM_SAE_KEY_ATTR_BSSID,
+ BRCM_SAE_KEY_ATTR_PMK,
+ BRCM_SAE_KEY_ATTR_PMKID
+};
+#endif /* CONFIG_BRCM_SAE */
+
+enum wl_vendor_attr_acs_offload {
+ BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+ BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ,
+ BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ,
+ BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+ BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
+
+ BRCM_VENDOR_ATTR_ACS_HW_MODE,
+ BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
+ BRCM_VENDOR_ATTR_ACS_CHWIDTH,
+ BRCM_VENDOR_ATTR_ACS_CH_LIST,
+ BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+
+ BRCM_VENDOR_ATTR_ACS_LAST
+};
+
+
+#endif /* BRCM_VENDOR_H */
diff --git a/contrib/wpa/src/common/common_module_tests.c b/contrib/wpa/src/common/common_module_tests.c
index 30c52476bbed..8aba713f92ba 100644
--- a/contrib/wpa/src/common/common_module_tests.c
+++ b/contrib/wpa/src/common/common_module_tests.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
@@ -255,96 +256,145 @@ static int sae_tests(void)
#ifdef CONFIG_SAE
struct sae_data sae;
int ret = -1;
- /* IEEE P802.11-REVmd/D2.1, Annex J.10 */
- const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
- const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+ /* IEEE Std 802.11-2020, Annex J.10 */
+ const u8 addr1[ETH_ALEN] = { 0x4d, 0x3f, 0x2f, 0xff, 0xe3, 0x87 };
+ const u8 addr2[ETH_ALEN] = { 0xa5, 0xd8, 0xaa, 0x95, 0x8e, 0x3c };
+ const char *ssid = "byteme";
const char *pw = "mekmitasdigoat";
const char *pwid = "psk4internet";
const u8 local_rand[] = {
- 0xa9, 0x06, 0xf6, 0x1e, 0x4d, 0x3a, 0x5d, 0x4e,
- 0xb2, 0x96, 0x5f, 0xf3, 0x4c, 0xf9, 0x17, 0xdd,
- 0x04, 0x44, 0x45, 0xc8, 0x78, 0xc1, 0x7c, 0xa5,
- 0xd5, 0xb9, 0x37, 0x86, 0xda, 0x9f, 0x83, 0xcf
+ 0x99, 0x24, 0x65, 0xfd, 0x3d, 0xaa, 0x3c, 0x60,
+ 0xaa, 0x65, 0x65, 0xb7, 0xf6, 0x2a, 0x2a, 0x7f,
+ 0x2e, 0x12, 0xdd, 0x12, 0xf1, 0x98, 0xfa, 0xf4,
+ 0xfb, 0xed, 0x89, 0xd7, 0xff, 0x1a, 0xce, 0x94
};
const u8 local_mask[] = {
- 0x42, 0x34, 0xb4, 0xfb, 0x17, 0xaa, 0x43, 0x5c,
- 0x52, 0xfb, 0xfd, 0xeb, 0xe6, 0x40, 0x39, 0xb4,
- 0x34, 0x78, 0x20, 0x0e, 0x54, 0xff, 0x7b, 0x6e,
- 0x07, 0xb6, 0x9c, 0xad, 0x74, 0x15, 0x3c, 0x15
+ 0x95, 0x07, 0xa9, 0x0f, 0x77, 0x7a, 0x04, 0x4d,
+ 0x6a, 0x08, 0x30, 0xb9, 0x1e, 0xa3, 0xd5, 0xdd,
+ 0x70, 0xbe, 0xce, 0x44, 0xe1, 0xac, 0xff, 0xb8,
+ 0x69, 0x83, 0xb5, 0xe1, 0xbf, 0x9f, 0xb3, 0x22
};
const u8 local_commit[] = {
- 0x13, 0x00, 0xeb, 0x3b, 0xab, 0x19, 0x64, 0xe4,
- 0xa0, 0xab, 0x05, 0x92, 0x5d, 0xdf, 0x33, 0x39,
- 0x51, 0x91, 0x38, 0xbc, 0x65, 0xd6, 0xcd, 0xc0,
- 0xf8, 0x13, 0xdd, 0x6f, 0xd4, 0x34, 0x4e, 0xb4,
- 0xbf, 0xe4, 0x4b, 0x5c, 0x21, 0x59, 0x76, 0x58,
- 0xf4, 0xe3, 0xed, 0xdf, 0xb4, 0xb9, 0x9f, 0x25,
- 0xb4, 0xd6, 0x54, 0x0f, 0x32, 0xff, 0x1f, 0xd5,
- 0xc5, 0x30, 0xc6, 0x0a, 0x79, 0x44, 0x48, 0x61,
- 0x0b, 0xc6, 0xde, 0x3d, 0x92, 0xbd, 0xbb, 0xd4,
- 0x7d, 0x93, 0x59, 0x80, 0xca, 0x6c, 0xf8, 0x98,
- 0x8a, 0xb6, 0x63, 0x0b, 0xe6, 0x76, 0x4c, 0x88,
- 0x5c, 0xeb, 0x97, 0x93, 0x97, 0x0f, 0x69, 0x52,
- 0x17, 0xee, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
- 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74
+ 0x13, 0x00, 0x2e, 0x2c, 0x0f, 0x0d, 0xb5, 0x24,
+ 0x40, 0xad, 0x14, 0x6d, 0x96, 0x71, 0x14, 0xce,
+ 0x00, 0x5c, 0xe1, 0xea, 0xb0, 0xaa, 0x2c, 0x2e,
+ 0x5c, 0x28, 0x71, 0xb7, 0x74, 0xf6, 0xc2, 0x57,
+ 0x5c, 0x65, 0xd5, 0xad, 0x9e, 0x00, 0x82, 0x97,
+ 0x07, 0xaa, 0x36, 0xba, 0x8b, 0x85, 0x97, 0x38,
+ 0xfc, 0x96, 0x1d, 0x08, 0x24, 0x35, 0x05, 0xf4,
+ 0x7c, 0x03, 0x53, 0x76, 0xd7, 0xac, 0x4b, 0xc8,
+ 0xd7, 0xb9, 0x50, 0x83, 0xbf, 0x43, 0x82, 0x7d,
+ 0x0f, 0xc3, 0x1e, 0xd7, 0x78, 0xdd, 0x36, 0x71,
+ 0xfd, 0x21, 0xa4, 0x6d, 0x10, 0x91, 0xd6, 0x4b,
+ 0x6f, 0x9a, 0x1e, 0x12, 0x72, 0x62, 0x13, 0x25,
+ 0xdb, 0xe1
};
const u8 peer_commit[] = {
- 0x13, 0x00, 0x55, 0x64, 0xf0, 0x45, 0xb2, 0xea,
- 0x1e, 0x56, 0x6c, 0xf1, 0xdd, 0x74, 0x1f, 0x70,
- 0xd9, 0xbe, 0x35, 0xd2, 0xdf, 0x5b, 0x9a, 0x55,
- 0x02, 0x94, 0x6e, 0xe0, 0x3c, 0xf8, 0xda, 0xe2,
- 0x7e, 0x1e, 0x05, 0xb8, 0x43, 0x0e, 0xb7, 0xa9,
- 0x9e, 0x24, 0x87, 0x7c, 0xe6, 0x9b, 0xaf, 0x3d,
- 0xc5, 0x80, 0xe3, 0x09, 0x63, 0x3d, 0x6b, 0x38,
- 0x5f, 0x83, 0xee, 0x1c, 0x3e, 0xc3, 0x59, 0x1f,
- 0x1a, 0x53, 0x93, 0xc0, 0x6e, 0x80, 0x5d, 0xdc,
- 0xeb, 0x2f, 0xde, 0x50, 0x93, 0x0d, 0xd7, 0xcf,
- 0xeb, 0xb9, 0x87, 0xc6, 0xff, 0x96, 0x66, 0xaf,
- 0x16, 0x4e, 0xb5, 0x18, 0x4d, 0x8e, 0x66, 0x62,
- 0xed, 0x6a, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
- 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74
+ 0x13, 0x00, 0x59, 0x1b, 0x96, 0xf3, 0x39, 0x7f,
+ 0xb9, 0x45, 0x10, 0x08, 0x48, 0xe7, 0xb5, 0x50,
+ 0x54, 0x3b, 0x67, 0x20, 0xd8, 0x83, 0x37, 0xee,
+ 0x93, 0xfc, 0x49, 0xfd, 0x6d, 0xf7, 0xe0, 0x8b,
+ 0x52, 0x23, 0xe7, 0x1b, 0x9b, 0xb0, 0x48, 0xd3,
+ 0x87, 0x3f, 0x20, 0x55, 0x69, 0x53, 0xa9, 0x6c,
+ 0x91, 0x53, 0x6f, 0xd8, 0xee, 0x6c, 0xa9, 0xb4,
+ 0xa6, 0x8a, 0x14, 0x8b, 0x05, 0x6a, 0x90, 0x9b,
+ 0xe0, 0x3e, 0x83, 0xae, 0x20, 0x8f, 0x60, 0xf8,
+ 0xef, 0x55, 0x37, 0x85, 0x80, 0x74, 0xdb, 0x06,
+ 0x68, 0x70, 0x32, 0x39, 0x98, 0x62, 0x99, 0x9b,
+ 0x51, 0x1e, 0x0a, 0x15, 0x52, 0xa5, 0xfe, 0xa3,
+ 0x17, 0xc2
};
const u8 kck[] = {
- 0x59, 0x9d, 0x6f, 0x1e, 0x27, 0x54, 0x8b, 0xe8,
- 0x49, 0x9d, 0xce, 0xed, 0x2f, 0xec, 0xcf, 0x94,
- 0x81, 0x8c, 0xe1, 0xc7, 0x9f, 0x1b, 0x4e, 0xb3,
- 0xd6, 0xa5, 0x32, 0x28, 0xa0, 0x9b, 0xf3, 0xed
+ 0x1e, 0x73, 0x3f, 0x6d, 0x9b, 0xd5, 0x32, 0x56,
+ 0x28, 0x73, 0x04, 0x33, 0x88, 0x31, 0xb0, 0x9a,
+ 0x39, 0x40, 0x6d, 0x12, 0x10, 0x17, 0x07, 0x3a,
+ 0x5c, 0x30, 0xdb, 0x36, 0xf3, 0x6c, 0xb8, 0x1a
};
const u8 pmk[] = {
- 0x7a, 0xea, 0xd8, 0x6f, 0xba, 0x4c, 0x32, 0x21,
- 0xfc, 0x43, 0x7f, 0x5f, 0x14, 0xd7, 0x0d, 0x85,
- 0x4e, 0xa5, 0xd5, 0xaa, 0xc1, 0x69, 0x01, 0x16,
- 0x79, 0x30, 0x81, 0xed, 0xa4, 0xd5, 0x57, 0xc5
+ 0x4e, 0x4d, 0xfa, 0xb1, 0xa2, 0xdd, 0x8a, 0xc1,
+ 0xa9, 0x17, 0x90, 0xf9, 0x53, 0xfa, 0xaa, 0x45,
+ 0x2a, 0xe5, 0xc6, 0x87, 0x3a, 0xb7, 0x5b, 0x63,
+ 0x60, 0x5b, 0xa6, 0x63, 0xf8, 0xa7, 0xfe, 0x59
};
const u8 pmkid[] = {
- 0x40, 0xa0, 0x9b, 0x60, 0x17, 0xce, 0xbf, 0x00,
- 0x72, 0x84, 0x3b, 0x53, 0x52, 0xaa, 0x2b, 0x4f
- };
- const u8 local_confirm[] = {
- 0x01, 0x00, 0x12, 0xd9, 0xd5, 0xc7, 0x8c, 0x50,
- 0x05, 0x26, 0xd3, 0x6c, 0x41, 0xdb, 0xc5, 0x6a,
- 0xed, 0xf2, 0x91, 0x4c, 0xed, 0xdd, 0xd7, 0xca,
- 0xd4, 0xa5, 0x8c, 0x48, 0xf8, 0x3d, 0xbd, 0xe9,
- 0xfc, 0x77
- };
- const u8 peer_confirm[] = {
- 0x01, 0x00, 0x02, 0x87, 0x1c, 0xf9, 0x06, 0x89,
- 0x8b, 0x80, 0x60, 0xec, 0x18, 0x41, 0x43, 0xbe,
- 0x77, 0xb8, 0xc0, 0x8a, 0x80, 0x19, 0xb1, 0x3e,
- 0xb6, 0xd0, 0xae, 0xf0, 0xd8, 0x38, 0x3d, 0xfa,
- 0xc2, 0xfd
+ 0x87, 0x47, 0xa6, 0x00, 0xee, 0xa3, 0xf9, 0xf2,
+ 0x24, 0x75, 0xdf, 0x58, 0xca, 0x1e, 0x54, 0x98
};
struct wpabuf *buf = NULL;
struct crypto_bignum *mask = NULL;
+ const u8 pwe_19_x[32] = {
+ 0xc9, 0x30, 0x49, 0xb9, 0xe6, 0x40, 0x00, 0xf8,
+ 0x48, 0x20, 0x16, 0x49, 0xe9, 0x99, 0xf2, 0xb5,
+ 0xc2, 0x2d, 0xea, 0x69, 0xb5, 0x63, 0x2c, 0x9d,
+ 0xf4, 0xd6, 0x33, 0xb8, 0xaa, 0x1f, 0x6c, 0x1e
+ };
+ const u8 pwe_19_y[32] = {
+ 0x73, 0x63, 0x4e, 0x94, 0xb5, 0x3d, 0x82, 0xe7,
+ 0x38, 0x3a, 0x8d, 0x25, 0x81, 0x99, 0xd9, 0xdc,
+ 0x1a, 0x5e, 0xe8, 0x26, 0x9d, 0x06, 0x03, 0x82,
+ 0xcc, 0xbf, 0x33, 0xe6, 0x14, 0xff, 0x59, 0xa0
+ };
+ const u8 pwe_15[384] = {
+ 0x69, 0x68, 0x73, 0x65, 0x8f, 0x65, 0x31, 0x42,
+ 0x9f, 0x97, 0x39, 0x6f, 0xb8, 0x5f, 0x89, 0xe1,
+ 0xfc, 0xd2, 0xf6, 0x92, 0x19, 0xa9, 0x0e, 0x82,
+ 0x2f, 0xf7, 0xf4, 0xbc, 0x0b, 0xd8, 0xa7, 0x9f,
+ 0xf0, 0x80, 0x35, 0x31, 0x6f, 0xca, 0xe1, 0xa5,
+ 0x39, 0x77, 0xdc, 0x11, 0x2b, 0x0b, 0xfe, 0x2e,
+ 0x6f, 0x65, 0x6d, 0xc7, 0xd4, 0xa4, 0x5b, 0x08,
+ 0x1f, 0xd9, 0xbb, 0xe2, 0x22, 0x85, 0x31, 0x81,
+ 0x79, 0x70, 0xbe, 0xa1, 0x66, 0x58, 0x4a, 0x09,
+ 0x3c, 0x57, 0x34, 0x3c, 0x9d, 0x57, 0x8f, 0x42,
+ 0x58, 0xd0, 0x39, 0x81, 0xdb, 0x8f, 0x79, 0xa2,
+ 0x1b, 0x01, 0xcd, 0x27, 0xc9, 0xae, 0xcf, 0xcb,
+ 0x9c, 0xdb, 0x1f, 0x84, 0xb8, 0x88, 0x4e, 0x8f,
+ 0x50, 0x66, 0xb4, 0x29, 0x83, 0x1e, 0xb9, 0x89,
+ 0x0c, 0xa5, 0x47, 0x21, 0xba, 0x10, 0xd5, 0xaa,
+ 0x1a, 0x80, 0xce, 0xf1, 0x4c, 0xad, 0x16, 0xda,
+ 0x57, 0xb2, 0x41, 0x8a, 0xbe, 0x4b, 0x8c, 0xb0,
+ 0xb2, 0xeb, 0xf7, 0xa8, 0x0e, 0x3e, 0xcf, 0x22,
+ 0x8f, 0xd8, 0xb6, 0xdb, 0x79, 0x9c, 0x9b, 0x80,
+ 0xaf, 0xd7, 0x14, 0xad, 0x51, 0x82, 0xf4, 0x64,
+ 0xb6, 0x3f, 0x4c, 0x6c, 0xe5, 0x3f, 0xaa, 0x6f,
+ 0xbf, 0x3d, 0xc2, 0x3f, 0x77, 0xfd, 0xcb, 0xe1,
+ 0x9c, 0xe3, 0x1e, 0x8a, 0x0e, 0x97, 0xe2, 0x2b,
+ 0xe2, 0xdd, 0x37, 0x39, 0x88, 0xc2, 0x8e, 0xbe,
+ 0xfa, 0xac, 0x3d, 0x5b, 0x62, 0x2e, 0x1e, 0x74,
+ 0xa0, 0x9a, 0xf8, 0xed, 0xfa, 0xe1, 0xce, 0x9c,
+ 0xab, 0xbb, 0xdc, 0x36, 0xb1, 0x28, 0x46, 0x3c,
+ 0x7e, 0xa8, 0xbd, 0xb9, 0x36, 0x4c, 0x26, 0x75,
+ 0xe0, 0x17, 0x73, 0x1f, 0xe0, 0xfe, 0xf6, 0x49,
+ 0xfa, 0xa0, 0x45, 0xf4, 0x44, 0x05, 0x20, 0x27,
+ 0x25, 0xc2, 0x99, 0xde, 0x27, 0x8b, 0x70, 0xdc,
+ 0x54, 0x60, 0x90, 0x02, 0x1e, 0x29, 0x97, 0x9a,
+ 0xc4, 0xe7, 0xb6, 0xf5, 0x8b, 0xae, 0x7c, 0x34,
+ 0xaa, 0xef, 0x9b, 0xc6, 0x30, 0xf2, 0x80, 0x8d,
+ 0x80, 0x78, 0xc2, 0x55, 0x63, 0xa0, 0xa1, 0x38,
+ 0x70, 0xfb, 0xf4, 0x74, 0x8d, 0xcd, 0x87, 0x90,
+ 0xb4, 0x54, 0xc3, 0x75, 0xdf, 0x10, 0xc5, 0xb6,
+ 0xb2, 0x08, 0x59, 0x61, 0xe6, 0x68, 0xa5, 0x82,
+ 0xf8, 0x8f, 0x47, 0x30, 0x43, 0xb4, 0xdc, 0x31,
+ 0xfc, 0xbc, 0x69, 0xe7, 0xb4, 0x94, 0xb0, 0x6a,
+ 0x60, 0x59, 0x80, 0x2e, 0xd3, 0xa4, 0xe8, 0x97,
+ 0xa2, 0xa3, 0xc9, 0x08, 0x4b, 0x27, 0x6c, 0xc1,
+ 0x37, 0xe8, 0xfc, 0x5c, 0xe2, 0x54, 0x30, 0x3e,
+ 0xf8, 0xfe, 0xa2, 0xfc, 0xbb, 0xbd, 0x88, 0x6c,
+ 0x92, 0xa3, 0x2a, 0x40, 0x7a, 0x2c, 0x22, 0x38,
+ 0x8c, 0x86, 0x86, 0xfe, 0xb9, 0xd4, 0x6b, 0xd6,
+ 0x47, 0x88, 0xa7, 0xf6, 0x8e, 0x0f, 0x14, 0xad,
+ 0x1e, 0xac, 0xcf, 0x33, 0x01, 0x99, 0xc1, 0x62
+ };
+ int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
+ struct sae_pt *pt_info, *pt;
+ const u8 addr1b[ETH_ALEN] = { 0x00, 0x09, 0x5b, 0x66, 0xec, 0x1e };
+ const u8 addr2b[ETH_ALEN] = { 0x00, 0x0b, 0x6b, 0xd9, 0x02, 0x46 };
os_memset(&sae, 0, sizeof(sae));
buf = wpabuf_alloc(1000);
if (!buf ||
sae_set_group(&sae, 19) < 0 ||
sae_prepare_commit(addr1, addr2, (const u8 *) pw, os_strlen(pw),
- pwid, &sae) < 0)
+ &sae) < 0)
goto fail;
/* Override local values based on SAE test vector */
@@ -366,7 +416,8 @@ static int sae_tests(void)
goto fail;
/* Check that output matches the test vector */
- sae_write_commit(&sae, buf, NULL, pwid);
+ if (sae_write_commit(&sae, buf, NULL, NULL) < 0)
+ goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
if (wpabuf_len(buf) != sizeof(local_commit) ||
@@ -377,7 +428,7 @@ static int sae_tests(void)
}
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
- NULL) != 0 ||
+ NULL, 0) != 0 ||
sae_process_commit(&sae) < 0)
goto fail;
@@ -396,20 +447,61 @@ static int sae_tests(void)
goto fail;
}
- buf->used = 0;
- sae.send_confirm = 1;
- sae_write_confirm(&sae, buf);
- wpa_hexdump_buf(MSG_DEBUG, "SAE: Confirm message", buf);
-
- if (wpabuf_len(buf) != sizeof(local_confirm) ||
- os_memcmp(wpabuf_head(buf), local_confirm,
- sizeof(local_confirm)) != 0) {
- wpa_printf(MSG_ERROR, "SAE: Mismatch in local confirm");
+ pt_info = sae_derive_pt(pt_groups,
+ (const u8 *) ssid, os_strlen(ssid),
+ (const u8 *) pw, os_strlen(pw), pwid);
+ if (!pt_info)
goto fail;
+
+ for (pt = pt_info; pt; pt = pt->next) {
+ if (pt->group == 19) {
+ struct crypto_ec_point *pwe;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len = sizeof(pwe_19_x);
+
+ pwe = sae_derive_pwe_from_pt_ecc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_ec_point_to_bin(pt->ec, pwe, bin,
+ bin + prime_len) < 0 ||
+ os_memcmp(pwe_19_x, bin, prime_len) != 0 ||
+ os_memcmp(pwe_19_y, bin + prime_len,
+ prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_ec_point_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_ec_point_deinit(pwe, 1);
+ }
+
+ if (pt->group == 15) {
+ struct crypto_bignum *pwe;
+ u8 bin[SAE_MAX_PRIME_LEN];
+ size_t prime_len = sizeof(pwe_15);
+
+ pwe = sae_derive_pwe_from_pt_ffc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(pwe, bin, sizeof(bin),
+ prime_len) < 0 ||
+ os_memcmp(pwe_15, bin, prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_bignum_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_bignum_deinit(pwe, 1);
+ }
}
- if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
- goto fail;
+ sae_deinit_pt(pt_info);
ret = 0;
fail:
@@ -423,6 +515,267 @@ fail:
}
+static int sae_pk_tests(void)
+{
+#ifdef CONFIG_SAE_PK
+ const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
+ struct {
+ const char *pw;
+ const u8 *val;
+ } valid[] = {
+ { "a2bc-de3f-ghim", (u8 *) "\x06\x82\x21\x93\x65\x31\xd0\xc0" },
+ { "aaaa-aaaa-aaaj", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x90" },
+ { "7777-7777-777f", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe\x50" },
+ { NULL, NULL }
+ };
+ int i;
+ bool failed;
+
+ for (i = 0; invalid[i]; i++) {
+ if (sae_pk_valid_password(invalid[i])) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Invalid password '%s' not recognized",
+ invalid[i]);
+ return -1;
+ }
+ }
+
+ failed = false;
+ for (i = 0; valid[i].pw; i++) {
+ u8 *res;
+ size_t res_len;
+ char *b32;
+ const char *pw = valid[i].pw;
+ const u8 *val = valid[i].val;
+ size_t pw_len = os_strlen(pw);
+ size_t bits = (pw_len - pw_len / 5) * 5;
+ size_t bytes = (bits + 7) / 8;
+
+ if (!sae_pk_valid_password(pw)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Valid password '%s' not recognized",
+ pw);
+ failed = true;
+ continue;
+ }
+
+ res = sae_pk_base32_decode(pw, pw_len, &res_len);
+ if (!res) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to decode password '%s'",
+ valid[i].pw);
+ failed = true;
+ continue;
+ }
+ if (res_len != bytes || os_memcmp(val, res, res_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for decoded password '%s'",
+ valid[i].pw);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Decoded value",
+ res, res_len);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Expected value",
+ val, bytes);
+ failed = true;
+ }
+ os_free(res);
+
+ b32 = sae_pk_base32_encode(val, bits - 5);
+ if (!b32) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to encode password '%s'",
+ pw);
+ failed = true;
+ continue;
+ }
+ if (os_strcmp(b32, pw) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for password '%s'", pw);
+ wpa_printf(MSG_INFO, "SAE-PK: Encoded value: '%s'",
+ b32);
+ failed = true;
+ }
+ os_free(b32);
+ }
+
+ return failed ? -1 : 0;
+#else /* CONFIG_SAE_PK */
+ return 0;
+#endif /* CONFIG_SAE_PK */
+}
+
+
+#ifdef CONFIG_PASN
+
+static int pasn_test_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.12 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+
+ const u8 spa_addr[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 bssid[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 dhss[] = {
+ 0xf8, 0x7b, 0x20, 0x8e, 0x7e, 0xd2, 0xb7, 0x37,
+ 0xaf, 0xdb, 0xc2, 0xe1, 0x3e, 0xae, 0x78, 0xda,
+ 0x30, 0x01, 0x23, 0xd4, 0xd8, 0x4b, 0xa8, 0xb0,
+ 0xea, 0xfe, 0x90, 0xc4, 0x8c, 0xdf, 0x1f, 0x93
+ };
+ const u8 kck[] = {
+ 0x7b, 0xb8, 0x21, 0xac, 0x0a, 0xa5, 0x90, 0x9d,
+ 0xd6, 0x54, 0xa5, 0x60, 0x65, 0xad, 0x7c, 0x77,
+ 0xeb, 0x88, 0x9c, 0xbe, 0x29, 0x05, 0xbb, 0xf0,
+ 0x5a, 0xbb, 0x1e, 0xea, 0xc8, 0x8b, 0xa3, 0x06
+ };
+ const u8 tk[] = {
+ 0x67, 0x3e, 0xab, 0x46, 0xb8, 0x32, 0xd5, 0xa8,
+ 0x0c, 0xbc, 0x02, 0x43, 0x01, 0x6e, 0x20, 0x7e
+ };
+ const u8 kdk[] = {
+ 0x2d, 0x0f, 0x0e, 0x82, 0xc7, 0x0d, 0xd2, 0x6b,
+ 0x79, 0x06, 0x1a, 0x46, 0x81, 0xe8, 0xdb, 0xb2,
+ 0xea, 0x83, 0xbe, 0xa3, 0x99, 0x84, 0x4b, 0xd5,
+ 0x89, 0x4e, 0xb3, 0x20, 0xf6, 0x9d, 0x7d, 0xd6
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = pasn_pmk_to_ptk(pmk, sizeof(pmk),
+ spa_addr, bssid,
+ dhss, sizeof(dhss),
+ &ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
+ WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int pasn_test_no_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.13 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+ const u8 aa[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 spa[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 anonce[] = {
+ 0xbe, 0x7a, 0x1c, 0xa2, 0x84, 0x34, 0x7b, 0x5b,
+ 0xd6, 0x7d, 0xbd, 0x2d, 0xfd, 0xb4, 0xd9, 0x9f,
+ 0x1a, 0xfa, 0xe0, 0xb8, 0x8b, 0xa1, 0x8e, 0x00,
+ 0x87, 0x18, 0x41, 0x7e, 0x4b, 0x27, 0xef, 0x5f
+ };
+ const u8 snonce[] = {
+ 0x40, 0x4b, 0x01, 0x2f, 0xfb, 0x43, 0xed, 0x0f,
+ 0xb4, 0x3e, 0xa1, 0xf2, 0x87, 0xc9, 0x1f, 0x25,
+ 0x06, 0xd2, 0x1b, 0x4a, 0x92, 0xd7, 0x4b, 0x5e,
+ 0xa5, 0x0c, 0x94, 0x33, 0x50, 0xce, 0x86, 0x71
+ };
+ const u8 kck[] = {
+ 0xcd, 0x7b, 0x9e, 0x75, 0x55, 0x36, 0x2d, 0xf0,
+ 0xb6, 0x35, 0x68, 0x48, 0x4a, 0x81, 0x12, 0xf5
+ };
+ const u8 kek[] = {
+ 0x99, 0xca, 0xd3, 0x58, 0x8d, 0xa0, 0xf1, 0xe6,
+ 0x3f, 0xd1, 0x90, 0x19, 0x10, 0x39, 0xbb, 0x4b
+ };
+ const u8 tk[] = {
+ 0x9e, 0x2e, 0x93, 0x77, 0xe7, 0x53, 0x2e, 0x73,
+ 0x7a, 0x1b, 0xc2, 0x50, 0xfe, 0x19, 0x4a, 0x03
+ };
+ const u8 kdk[] = {
+ 0x6c, 0x7f, 0xb9, 0x7c, 0xeb, 0x55, 0xb0, 0x1a,
+ 0xcf, 0xf0, 0x0f, 0x07, 0x09, 0x42, 0xbd, 0xf5,
+ 0x29, 0x1f, 0xeb, 0x4b, 0xee, 0x38, 0xe0, 0x36,
+ 0x5b, 0x25, 0xa2, 0x50, 0xbb, 0x2a, 0xc9, 0xff
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = wpa_pmk_to_ptk(pmk, sizeof(pmk),
+ "Pairwise key expansion",
+ spa, aa, snonce, anonce,
+ &ptk, WPA_KEY_MGMT_SAE, WPA_CIPHER_CCMP,
+ NULL, 0, WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.kek_len != sizeof(kek) ||
+ os_memcmp(kek, ptk.kek, sizeof(kek)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KEK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
+
+static int pasn_tests(void)
+{
+#ifdef CONFIG_PASN
+ if (pasn_test_pasn_auth() ||
+ pasn_test_no_pasn_auth())
+ return -1;
+#endif /* CONFIG_PASN */
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -432,6 +785,8 @@ int common_module_tests(void)
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
sae_tests() < 0 ||
+ sae_pk_tests() < 0 ||
+ pasn_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/contrib/wpa/src/common/defs.h b/contrib/wpa/src/common/defs.h
index 4faf1c8601d0..f43bdb5d1b15 100644
--- a/contrib/wpa/src/common/defs.h
+++ b/contrib/wpa/src/common/defs.h
@@ -9,15 +9,6 @@
#ifndef DEFS_H
#define DEFS_H
-#ifdef FALSE
-#undef FALSE
-#endif
-#ifdef TRUE
-#undef TRUE
-#endif
-typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-
-
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
@@ -58,6 +49,8 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_KEY_MGMT_OWE BIT(22)
#define WPA_KEY_MGMT_DPP BIT(23)
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+#define WPA_KEY_MGMT_PASN BIT(25)
+
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
WPA_KEY_MGMT_FT_IEEE8021X | \
@@ -82,6 +75,13 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
WPA_KEY_MGMT_FT_FILS_SHA384));
}
+static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256));
+}
+
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
@@ -192,8 +192,7 @@ enum wpa_alg {
WPA_ALG_WEP,
WPA_ALG_TKIP,
WPA_ALG_CCMP,
- WPA_ALG_IGTK,
- WPA_ALG_PMK,
+ WPA_ALG_BIP_CMAC_128,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK,
@@ -204,6 +203,14 @@ enum wpa_alg {
WPA_ALG_BIP_CMAC_256
};
+static inline int wpa_alg_bip(enum wpa_alg alg)
+{
+ return alg == WPA_ALG_BIP_CMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256;
+}
+
/**
* enum wpa_states - wpa_supplicant state
*
@@ -383,9 +390,10 @@ enum mesh_plink_state {
};
enum set_band {
- WPA_SETBAND_AUTO,
- WPA_SETBAND_5G,
- WPA_SETBAND_2G
+ WPA_SETBAND_AUTO = 0,
+ WPA_SETBAND_5G = BIT(0),
+ WPA_SETBAND_2G = BIT(1),
+ WPA_SETBAND_6G = BIT(2),
};
enum wpa_radio_work_band {
@@ -397,7 +405,8 @@ enum wpa_radio_work_band {
enum beacon_rate_type {
BEACON_RATE_LEGACY,
BEACON_RATE_HT,
- BEACON_RATE_VHT
+ BEACON_RATE_VHT,
+ BEACON_RATE_HE
};
enum eap_proxy_sim_state {
@@ -416,7 +425,54 @@ enum chan_width {
CHAN_WIDTH_80,
CHAN_WIDTH_80P80,
CHAN_WIDTH_160,
+ CHAN_WIDTH_2160,
+ CHAN_WIDTH_4320,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_8640,
CHAN_WIDTH_UNKNOWN
};
+enum key_flag {
+ KEY_FLAG_MODIFY = BIT(0),
+ KEY_FLAG_DEFAULT = BIT(1),
+ KEY_FLAG_RX = BIT(2),
+ KEY_FLAG_TX = BIT(3),
+ KEY_FLAG_GROUP = BIT(4),
+ KEY_FLAG_PAIRWISE = BIT(5),
+ KEY_FLAG_PMK = BIT(6),
+ /* Used flag combinations */
+ KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX,
+ KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT = KEY_FLAG_GROUP_RX_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_GROUP_RX = KEY_FLAG_GROUP | KEY_FLAG_RX,
+ KEY_FLAG_GROUP_TX_DEFAULT = KEY_FLAG_GROUP | KEY_FLAG_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_PAIRWISE_RX_TX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+ KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
+ KEY_FLAG_MODIFY,
+ /* Max allowed flags for each key type */
+ KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+ KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
+ KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
+};
+
+static inline int check_key_flag(enum key_flag key_flag)
+{
+ return !!(!key_flag ||
+ ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
+ (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
+ ((key_flag & KEY_FLAG_GROUP) &&
+ (key_flag & ~KEY_FLAG_GROUP_MASK)) ||
+ ((key_flag & KEY_FLAG_PMK) &&
+ (key_flag & ~KEY_FLAG_PMK_MASK)));
+}
+
+enum ptk0_rekey_handling {
+ PTK0_REKEY_ALLOW_ALWAYS,
+ PTK0_REKEY_ALLOW_LOCAL_OK,
+ PTK0_REKEY_ALLOW_NEVER
+};
+
#endif /* DEFS_H */
diff --git a/contrib/wpa/src/common/dhcp.h b/contrib/wpa/src/common/dhcp.h
index ff52483b12eb..c7f0617dd928 100644
--- a/contrib/wpa/src/common/dhcp.h
+++ b/contrib/wpa/src/common/dhcp.h
@@ -57,7 +57,7 @@ struct dhcp_data {
} STRUCT_PACKED;
struct bootp_pkt {
- struct iphdr iph;
+ struct ip iph;
struct udphdr udph;
u8 op;
u8 htype;
diff --git a/contrib/wpa/src/common/dpp.c b/contrib/wpa/src/common/dpp.c
index dcbc80b6b84b..3c8c7682d514 100644
--- a/contrib/wpa/src/common/dpp.c
+++ b/contrib/wpa/src/common/dpp.c
@@ -1,51 +1,41 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
-#include <fcntl.h>
#include <openssl/opensslv.h>
#include <openssl/err.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
-#include "utils/ip_addr.h"
-#include "utils/eloop.h"
#include "common/ieee802_11_common.h"
-#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/gas.h"
+#include "eap_common/eap_defs.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
-#include "crypto/sha384.h"
-#include "crypto/sha512.h"
#include "drivers/driver.h"
#include "dpp.h"
+#include "dpp_i.h"
+static const char * dpp_netrole_str(enum dpp_netrole netrole);
+
#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_DPP2
+int dpp_version_override = 2;
+#else
+int dpp_version_override = 1;
+#endif
enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
-u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-u8 dpp_pkex_ephemeral_key_override[600];
-size_t dpp_pkex_ephemeral_key_override_len = 0;
-u8 dpp_protocol_key_override[600];
-size_t dpp_protocol_key_override_len = 0;
-u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
-size_t dpp_nonce_override_len = 0;
-
-static int dpp_test_gen_invalid_key(struct wpabuf *msg,
- const struct dpp_curve_params *curve);
#endif /* CONFIG_TESTING_OPTIONS */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
@@ -53,649 +43,19 @@ static int dpp_test_gen_invalid_key(struct wpabuf *msg,
LIBRESSL_VERSION_NUMBER < 0x20700000L)
/* Compatibility wrappers for older versions. */
-static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
- sig->r = r;
- sig->s = s;
- return 1;
-}
-
-
-static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
- const BIGNUM **ps)
-{
- if (pr)
- *pr = sig->r;
- if (ps)
- *ps = sig->s;
-}
-
-#endif
-
-
-struct dpp_connection {
- struct dl_list list;
- struct dpp_controller *ctrl;
- struct dpp_relay_controller *relay;
- struct dpp_global *global;
- struct dpp_authentication *auth;
- int sock;
- u8 mac_addr[ETH_ALEN];
- unsigned int freq;
- u8 msg_len[4];
- size_t msg_len_octets;
- struct wpabuf *msg;
- struct wpabuf *msg_out;
- size_t msg_out_pos;
- unsigned int read_eloop:1;
- unsigned int write_eloop:1;
- unsigned int on_tcp_tx_complete_gas_done:1;
- unsigned int on_tcp_tx_complete_remove:1;
- unsigned int on_tcp_tx_complete_auth_ok:1;
-};
-
-/* Remote Controller */
-struct dpp_relay_controller {
- struct dl_list list;
- struct dpp_global *global;
- u8 pkhash[SHA256_MAC_LEN];
- struct hostapd_ip_addr ipaddr;
- void *cb_ctx;
- void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
- size_t len);
- void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
- int prot, struct wpabuf *buf);
- struct dl_list conn; /* struct dpp_connection */
-};
-
-/* Local Controller */
-struct dpp_controller {
- struct dpp_global *global;
- u8 allowed_roles;
- int qr_mutual;
- int sock;
- struct dl_list conn; /* struct dpp_connection */
- char *configurator_params;
-};
-
-struct dpp_global {
- void *msg_ctx;
- struct dl_list bootstrap; /* struct dpp_bootstrap_info */
- struct dl_list configurator; /* struct dpp_configurator */
#ifdef CONFIG_DPP2
- struct dl_list controllers; /* struct dpp_relay_controller */
- struct dpp_controller *controller;
- struct dl_list tcp_init; /* struct dpp_connection */
- void *cb_ctx;
- int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
-#endif /* CONFIG_DPP2 */
-};
-
-static const struct dpp_curve_params dpp_curves[] = {
- /* The mandatory to support and the default NIST P-256 curve needs to
- * be the first entry on this list. */
- { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
- { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
- { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
- { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
- { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
- { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
- { NULL, 0, 0, 0, 0, NULL, 0, NULL }
-};
-
-
-/* Role-specific elements for PKEX */
-
-/* NIST P-256 */
-static const u8 pkex_init_x_p256[32] = {
- 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
- 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
- 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
- 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
- };
-static const u8 pkex_init_y_p256[32] = {
- 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
- 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
- 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
- 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
- };
-static const u8 pkex_resp_x_p256[32] = {
- 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
- 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
- 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
- 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
-};
-static const u8 pkex_resp_y_p256[32] = {
- 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
- 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
- 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
- 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
-};
-
-/* NIST P-384 */
-static const u8 pkex_init_x_p384[48] = {
- 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
- 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
- 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
- 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
- 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
- 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
-};
-static const u8 pkex_init_y_p384[48] = {
- 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
- 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
- 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
- 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
- 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
- 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
-};
-static const u8 pkex_resp_x_p384[48] = {
- 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
- 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
- 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
- 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
- 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
- 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
-};
-static const u8 pkex_resp_y_p384[48] = {
- 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
- 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
- 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
- 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
- 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
- 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
-};
-
-/* NIST P-521 */
-static const u8 pkex_init_x_p521[66] = {
- 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
- 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
- 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
- 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
- 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
- 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
- 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
- 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
- 0x97, 0x76
-};
-static const u8 pkex_init_y_p521[66] = {
- 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
- 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
- 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
- 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
- 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
- 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
- 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
- 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
- 0x03, 0xa8
-};
-static const u8 pkex_resp_x_p521[66] = {
- 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
- 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
- 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
- 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
- 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
- 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
- 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
- 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
- 0x84, 0xb4
-};
-static const u8 pkex_resp_y_p521[66] = {
- 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
- 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
- 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
- 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
- 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
- 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
- 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
- 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
- 0xce, 0xe1
-};
-
-/* Brainpool P-256r1 */
-static const u8 pkex_init_x_bp_p256r1[32] = {
- 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
- 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
- 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
- 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
-};
-static const u8 pkex_init_y_bp_p256r1[32] = {
- 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
- 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
- 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
- 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
-};
-static const u8 pkex_resp_x_bp_p256r1[32] = {
- 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
- 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
- 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
- 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
-};
-static const u8 pkex_resp_y_bp_p256r1[32] = {
- 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
- 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
- 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
- 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
-};
-
-/* Brainpool P-384r1 */
-static const u8 pkex_init_x_bp_p384r1[48] = {
- 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
- 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
- 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
- 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
- 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
- 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
-};
-static const u8 pkex_init_y_bp_p384r1[48] = {
- 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
- 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
- 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
- 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
- 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
- 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
-};
-static const u8 pkex_resp_x_bp_p384r1[48] = {
- 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
- 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
- 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
- 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
- 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
- 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
-};
-static const u8 pkex_resp_y_bp_p384r1[48] = {
- 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
- 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
- 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
- 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
- 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
- 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
-};
-
-/* Brainpool P-512r1 */
-static const u8 pkex_init_x_bp_p512r1[64] = {
- 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
- 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
- 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
- 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
- 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
- 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
- 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
- 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
-};
-static const u8 pkex_init_y_bp_p512r1[64] = {
- 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
- 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
- 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
- 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
- 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
- 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
- 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
- 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
-};
-static const u8 pkex_resp_x_bp_p512r1[64] = {
- 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
- 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
- 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
- 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
- 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
- 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
- 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
- 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
-};
-static const u8 pkex_resp_y_bp_p512r1[64] = {
- 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
- 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
- 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
- 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
- 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
- 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
- 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
- 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
-};
-
-
-static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
- const EC_POINT *point)
-{
- BIGNUM *x, *y;
- BN_CTX *ctx;
- char *x_str = NULL, *y_str = NULL;
-
- if (!wpa_debug_show_keys)
- return;
-
- ctx = BN_CTX_new();
- x = BN_new();
- y = BN_new();
- if (!ctx || !x || !y ||
- EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
- goto fail;
-
- x_str = BN_bn2hex(x);
- y_str = BN_bn2hex(y);
- if (!x_str || !y_str)
- goto fail;
-
- wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
-
-fail:
- OPENSSL_free(x_str);
- OPENSSL_free(y_str);
- BN_free(x);
- BN_free(y);
- BN_CTX_free(ctx);
-}
-
-
-static int dpp_hash_vector(const struct dpp_curve_params *curve,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- if (curve->hash_len == 32)
- return sha256_vector(num_elem, addr, len, mac);
- if (curve->hash_len == 48)
- return sha384_vector(num_elem, addr, len, mac);
- if (curve->hash_len == 64)
- return sha512_vector(num_elem, addr, len, mac);
- return -1;
-}
-
-
-static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
- const char *label, u8 *out, size_t outlen)
-{
- if (hash_len == 32)
- return hmac_sha256_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- if (hash_len == 48)
- return hmac_sha384_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- if (hash_len == 64)
- return hmac_sha512_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- return -1;
-}
-
-
-static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- if (hash_len == 32)
- return hmac_sha256_vector(key, key_len, num_elem, addr, len,
- mac);
- if (hash_len == 48)
- return hmac_sha384_vector(key, key_len, num_elem, addr, len,
- mac);
- if (hash_len == 64)
- return hmac_sha512_vector(key, key_len, num_elem, addr, len,
- mac);
- return -1;
-}
-
-
-static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
- const u8 *data, size_t data_len, u8 *mac)
-{
- if (hash_len == 32)
- return hmac_sha256(key, key_len, data, data_len, mac);
- if (hash_len == 48)
- return hmac_sha384(key, key_len, data, data_len, mac);
- if (hash_len == 64)
- return hmac_sha512(key, key_len, data, data_len, mac);
- return -1;
-}
-
-
-static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
-{
- int num_bytes, offset;
-
- num_bytes = BN_num_bytes(bn);
- if ((size_t) num_bytes > len)
- return -1;
- offset = len - num_bytes;
- os_memset(pos, 0, offset);
- BN_bn2bin(bn, pos + offset);
- return 0;
-}
-
-
-static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
-{
- int len, res;
- EC_KEY *eckey;
- struct wpabuf *buf;
- unsigned char *pos;
-
- eckey = EVP_PKEY_get1_EC_KEY(pkey);
- if (!eckey)
- return NULL;
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
- len = i2o_ECPublicKey(eckey, NULL);
- if (len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to determine public key encoding length");
- EC_KEY_free(eckey);
- return NULL;
- }
-
- buf = wpabuf_alloc(len);
- if (!buf) {
- EC_KEY_free(eckey);
- return NULL;
- }
-
- pos = wpabuf_put(buf, len);
- res = i2o_ECPublicKey(eckey, &pos);
- EC_KEY_free(eckey);
- if (res != len) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to encode public key (res=%d/%d)",
- res, len);
- wpabuf_free(buf);
- return NULL;
- }
-
- if (!prefix) {
- /* Remove 0x04 prefix to match DPP definition */
- pos = wpabuf_mhead(buf);
- os_memmove(pos, pos + 1, len - 1);
- buf->used--;
- }
-
- return buf;
-}
-
-
-static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
- const u8 *buf_x, const u8 *buf_y,
- size_t len)
-{
- EC_KEY *eckey = NULL;
- BN_CTX *ctx;
- EC_POINT *point = NULL;
- BIGNUM *x = NULL, *y = NULL;
- EVP_PKEY *pkey = NULL;
-
- ctx = BN_CTX_new();
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- return NULL;
- }
-
- point = EC_POINT_new(group);
- x = BN_bin2bn(buf_x, len, NULL);
- y = BN_bin2bn(buf_y, len, NULL);
- if (!point || !x || !y) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- goto fail;
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
- wpa_printf(MSG_ERROR,
- "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx) ||
- EC_POINT_is_at_infinity(group, point)) {
- wpa_printf(MSG_ERROR, "DPP: Invalid point");
- goto fail;
- }
- dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
-
- eckey = EC_KEY_new();
- if (!eckey ||
- EC_KEY_set_group(eckey, group) != 1 ||
- EC_KEY_set_public_key(eckey, point) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to set EC_KEY: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
-
- pkey = EVP_PKEY_new();
- if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
- goto fail;
- }
-
-out:
- BN_free(x);
- BN_free(y);
- EC_KEY_free(eckey);
- EC_POINT_free(point);
- BN_CTX_free(ctx);
- return pkey;
-fail:
- EVP_PKEY_free(pkey);
- pkey = NULL;
- goto out;
-}
-
-
-static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
- const u8 *buf, size_t len)
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
{
- EC_KEY *eckey;
- const EC_GROUP *group;
- EVP_PKEY *pkey = NULL;
-
- if (len & 1)
- return NULL;
-
- eckey = EVP_PKEY_get1_EC_KEY(group_key);
- if (!eckey) {
- wpa_printf(MSG_ERROR,
- "DPP: Could not get EC_KEY from group_key");
+ if (pkey->type != EVP_PKEY_EC)
return NULL;
- }
-
- group = EC_KEY_get0_group(eckey);
- if (group)
- pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
- len / 2);
- else
- wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
-
- EC_KEY_free(eckey);
- return pkey;
+ return pkey->pkey.ec;
}
+#endif /* CONFIG_DPP2 */
-
-static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
- u8 *secret, size_t *secret_len)
-{
- EVP_PKEY_CTX *ctx;
- int ret = -1;
-
- ERR_clear_error();
- *secret_len = 0;
-
- ctx = EVP_PKEY_CTX_new(own, NULL);
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-
- if (EVP_PKEY_derive_init(ctx) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: EVP_PKEY_derive_set_peet failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- u8 buf[200];
- int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
-
- /* It looks like OpenSSL can return unexpectedly large buffer
- * need for shared secret from EVP_PKEY_derive(NULL) in some
- * cases. For example, group 19 has shown cases where secret_len
- * is set to 72 even though the actual length ends up being
- * updated to 32 when EVP_PKEY_derive() is called with a buffer
- * for the value. Work around this by trying to fetch the value
- * and continue if it is within supported range even when the
- * initial buffer need is claimed to be larger. */
- wpa_printf(level,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- if (*secret_len > 200)
- goto fail;
- if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- wpa_printf(MSG_ERROR,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- goto fail;
- }
- wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
- buf, *secret_len);
- os_memcpy(secret, buf, *secret_len);
- forced_memzero(buf, sizeof(buf));
- goto done;
- }
-
- if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
-done:
- ret = 0;
-
-fail:
- EVP_PKEY_CTX_free(ctx);
- return ret;
-}
+#endif
-static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
+void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
}
@@ -742,6 +102,34 @@ const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
}
+static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
+ u16 req_id, u16 *ret_len)
+{
+ u16 id, alen;
+ const u8 *pos, *end = buf + len;
+
+ if (!prev)
+ pos = buf;
+ else
+ pos = prev + WPA_GET_LE16(prev - 2);
+ while (end - pos >= 4) {
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (alen > end - pos)
+ return NULL;
+ if (id == req_id) {
+ *ret_len = alen;
+ return pos;
+ }
+ pos += alen;
+ }
+
+ return NULL;
+}
+
+
int dpp_check_attrs(const u8 *buf, size_t len)
{
const u8 *pos, *end;
@@ -790,7 +178,10 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
return;
os_free(info->uri);
os_free(info->info);
+ os_free(info->chan);
+ os_free(info->pk);
EVP_PKEY_free(info->pubkey);
+ str_clear_free(info->configurator_params);
os_free(info);
}
@@ -802,6 +193,8 @@ const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
return "QRCODE";
case DPP_BOOTSTRAP_PKEX:
return "PKEX";
+ case DPP_BOOTSTRAP_NFC_URI:
+ return "NFC-URI";
}
return "??";
}
@@ -852,6 +245,7 @@ int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
wpa_printf(MSG_DEBUG,
"DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
opclass, channel, freq);
+ bi->channels_listed = true;
if (freq < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
@@ -920,67 +314,38 @@ int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
}
-static const struct dpp_curve_params *
-dpp_get_curve_oid(const ASN1_OBJECT *poid)
+int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
{
- ASN1_OBJECT *oid;
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- oid = OBJ_txt2obj(dpp_curves[i].name, 0);
- if (oid && OBJ_cmp(poid, oid) == 0)
- return &dpp_curves[i];
- }
- return NULL;
-}
+#ifdef CONFIG_DPP2
+ if (!version || DPP_VERSION < 2)
+ return 0;
+ if (*version == '1')
+ bi->version = 1;
+ else if (*version == '2')
+ bi->version = 2;
+ else
+ wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
-static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
-{
- int i, tmp;
+ wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
+#endif /* CONFIG_DPP2 */
- if (!nid)
- return NULL;
- for (i = 0; dpp_curves[i].name; i++) {
- tmp = OBJ_txt2nid(dpp_curves[i].name);
- if (tmp == nid)
- return &dpp_curves[i];
- }
- return NULL;
+ return 0;
}
static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
{
- const char *end;
u8 *data;
size_t data_len;
- EVP_PKEY *pkey;
- const unsigned char *p;
int res;
- X509_PUBKEY *pub = NULL;
- ASN1_OBJECT *ppkalg;
- const unsigned char *pk;
- int ppklen;
- X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20800000L)
- ASN1_OBJECT *pa_oid;
-#else
- const ASN1_OBJECT *pa_oid;
-#endif
- const void *pval;
- int ptype;
- const ASN1_OBJECT *poid;
- char buf[100];
+ const char *end;
end = os_strchr(info, ';');
if (!end)
return -1;
- data = base64_decode((const unsigned char *) info, end - info,
- &data_len);
+ data = base64_decode(info, end - info, &data_len);
if (!data) {
wpa_printf(MSG_DEBUG,
"DPP: Invalid base64 encoding on URI public-key");
@@ -989,104 +354,9 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
data, data_len);
- if (sha256_vector(1, (const u8 **) &data, &data_len,
- bi->pubkey_hash) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- os_free(data);
- return -1;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
- bi->pubkey_hash, SHA256_MAC_LEN);
-
- /* DER encoded ASN.1 SubjectPublicKeyInfo
- *
- * SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING }
- *
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL }
- *
- * subjectPublicKey = compressed format public key per ANSI X9.63
- * algorithm = ecPublicKey (1.2.840.10045.2.1)
- * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
- * prime256v1 (1.2.840.10045.3.1.7)
- */
-
- p = data;
- pkey = d2i_PUBKEY(NULL, &p, data_len);
+ res = dpp_get_subject_public_key(bi, data, data_len);
os_free(data);
-
- if (!pkey) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
- return -1;
- }
-
- if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo does not describe an EC key");
- EVP_PKEY_free(pkey);
- return -1;
- }
-
- res = X509_PUBKEY_set(&pub, pkey);
- if (res != 1) {
- wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
- goto fail;
- }
-
- res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
- if (res != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters");
- goto fail;
- }
- res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo algorithm");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
- if (os_strcmp(buf, "id-ecPublicKey") != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo algorithm");
- goto fail;
- }
-
- X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
- if (ptype != V_ASN1_OBJECT) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
- goto fail;
- }
- poid = pval;
- res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
- bi->curve = dpp_get_curve_oid(poid);
- if (!bi->curve) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
- buf);
- goto fail;
- }
-
- wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
-
- X509_PUBKEY_free(pub);
- bi->pubkey = pkey;
- return 0;
-fail:
- X509_PUBKEY_free(pub);
- EVP_PKEY_free(pkey);
- return -1;
+ return res;
}
@@ -1095,6 +365,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
const char *pos = uri;
const char *end;
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
+ const char *version = NULL;
struct dpp_bootstrap_info *bi;
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -1125,6 +396,8 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
info = pos + 2;
else if (pos[0] == 'K' && pos[1] == ':' && !pk)
pk = pos + 2;
+ else if (pos[0] == 'V' && pos[1] == ':' && !version)
+ version = pos + 2;
else
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: Ignore unrecognized URI parameter",
@@ -1145,6 +418,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_parse_uri_version(bi, version) < 0 ||
dpp_parse_uri_pk(bi, pk) < 0) {
dpp_bootstrap_info_free(bi);
bi = NULL;
@@ -1154,486 +428,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
}
-struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_parse_uri(uri);
- if (bi)
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- return bi;
-}
-
-
-static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
-{
- EC_KEY *eckey;
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
- unsigned char *der = NULL;
- int der_len;
- const EC_GROUP *group;
- const EC_POINT *point;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- EVP_PKEY_print_private(out, key, 0, NULL);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (txt) {
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
- }
- os_free(txt);
- }
- BIO_free(out);
-
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!eckey)
- return;
-
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (group && point)
- dpp_debug_print_point(title, group, point);
-
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len > 0)
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
- OPENSSL_free(der);
- if (der_len <= 0) {
- der = NULL;
- der_len = i2d_EC_PUBKEY(eckey, &der);
- if (der_len > 0)
- wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
- OPENSSL_free(der);
- }
-
- EC_KEY_free(eckey);
-}
-
-
-static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
-{
- EVP_PKEY_CTX *kctx = NULL;
- EC_KEY *ec_params = NULL;
- EVP_PKEY *params = NULL, *key = NULL;
- int nid;
-
- wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
-
- nid = OBJ_txt2nid(curve->name);
- if (nid == NID_undef) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
- return NULL;
- }
-
- ec_params = EC_KEY_new_by_curve_name(nid);
- if (!ec_params) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EC_KEY parameters");
- goto fail;
- }
- EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
- params = EVP_PKEY_new();
- if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EVP_PKEY parameters");
- goto fail;
- }
-
- kctx = EVP_PKEY_CTX_new(params, NULL);
- if (!kctx ||
- EVP_PKEY_keygen_init(kctx) != 1 ||
- EVP_PKEY_keygen(kctx, &key) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
- key = NULL;
- goto fail;
- }
-
- if (wpa_debug_show_keys)
- dpp_debug_print_key("Own generated key", key);
-
-fail:
- EC_KEY_free(ec_params);
- EVP_PKEY_free(params);
- EVP_PKEY_CTX_free(kctx);
- return key;
-}
-
-
-static const struct dpp_curve_params *
-dpp_get_curve_name(const char *name)
-{
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- if (os_strcmp(name, dpp_curves[i].name) == 0 ||
- (dpp_curves[i].jwk_crv &&
- os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
-static const struct dpp_curve_params *
-dpp_get_curve_jwk_crv(const char *name)
-{
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- if (dpp_curves[i].jwk_crv &&
- os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
-static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len)
-{
- EVP_PKEY *pkey;
- EC_KEY *eckey;
- const EC_GROUP *group;
- int nid;
-
- pkey = EVP_PKEY_new();
- if (!pkey)
- return NULL;
- eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
- if (!eckey) {
- wpa_printf(MSG_INFO,
- "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- EVP_PKEY_free(pkey);
- return NULL;
- }
- group = EC_KEY_get0_group(eckey);
- if (!group) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
- nid = EC_GROUP_get_curve_name(group);
- *curve = dpp_get_curve_nid(nid);
- if (!*curve) {
- wpa_printf(MSG_INFO,
- "DPP: Unsupported curve (nid=%d) in pre-assigned key",
- nid);
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
-
- if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
- return pkey;
-}
-
-
-typedef struct {
- /* AlgorithmIdentifier ecPublicKey with optional parameters present
- * as an OID identifying the curve */
- X509_ALGOR *alg;
- /* Compressed format public key per ANSI X9.63 */
- ASN1_BIT_STRING *pub_key;
-} DPP_BOOTSTRAPPING_KEY;
-
-ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
-} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
-
-IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
-
-
-static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
-{
- unsigned char *der = NULL;
- int der_len;
- EC_KEY *eckey;
- struct wpabuf *ret = NULL;
- size_t len;
- const EC_GROUP *group;
- const EC_POINT *point;
- BN_CTX *ctx;
- DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
- int nid;
-
- ctx = BN_CTX_new();
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!ctx || !eckey)
- goto fail;
-
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (!group || !point)
- goto fail;
- dpp_debug_print_point("DPP: bootstrap public key", group, point);
- nid = EC_GROUP_get_curve_name(group);
-
- bootstrap = DPP_BOOTSTRAPPING_KEY_new();
- if (!bootstrap ||
- X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
- V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
- goto fail;
-
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- NULL, 0, ctx);
- if (len == 0)
- goto fail;
-
- der = OPENSSL_malloc(len);
- if (!der)
- goto fail;
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- der, len, ctx);
-
- OPENSSL_free(bootstrap->pub_key->data);
- bootstrap->pub_key->data = der;
- der = NULL;
- bootstrap->pub_key->length = len;
- /* No unused bits */
- bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
- bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
-
- der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
- if (der_len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to build DER encoded public key");
- goto fail;
- }
-
- ret = wpabuf_alloc_copy(der, der_len);
-fail:
- DPP_BOOTSTRAPPING_KEY_free(bootstrap);
- OPENSSL_free(der);
- EC_KEY_free(eckey);
- BN_CTX_free(ctx);
- return ret;
-}
-
-
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
-{
- struct wpabuf *der;
- int res;
- const u8 *addr[1];
- size_t len[1];
-
- der = dpp_bootstrap_key_der(bi->pubkey);
- if (!der)
- return -1;
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
- der);
-
- addr[0] = wpabuf_head(der);
- len[0] = wpabuf_len(der);
- res = sha256_vector(1, addr, len, bi->pubkey_hash);
- if (res < 0)
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- else
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
- wpabuf_free(der);
- return res;
-}
-
-
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len)
-{
- unsigned char *base64 = NULL;
- char *pos, *end;
- size_t len;
- struct wpabuf *der = NULL;
- const u8 *addr[1];
- int res;
-
- if (!curve) {
- bi->curve = &dpp_curves[0];
- } else {
- bi->curve = dpp_get_curve_name(curve);
- if (!bi->curve) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
- curve);
- return NULL;
- }
- }
- if (privkey)
- bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
- else
- bi->pubkey = dpp_gen_keypair(bi->curve);
- if (!bi->pubkey)
- goto fail;
- bi->own = 1;
-
- der = dpp_bootstrap_key_der(bi->pubkey);
- if (!der)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
- der);
-
- addr[0] = wpabuf_head(der);
- len = wpabuf_len(der);
- res = sha256_vector(1, addr, &len, bi->pubkey_hash);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
-
- base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
- wpabuf_free(der);
- der = NULL;
- if (!base64)
- goto fail;
- pos = (char *) base64;
- end = pos + len;
- for (;;) {
- pos = os_strchr(pos, '\n');
- if (!pos)
- break;
- os_memmove(pos, pos + 1, end - pos);
- }
- return (char *) base64;
-fail:
- os_free(base64);
- wpabuf_free(der);
- return NULL;
-}
-
-
-static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
- unsigned int hash_len)
-{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- const char *info = "first intermediate key";
- int res;
-
- /* k1 = HKDF(<>, "first intermediate key", M.x) */
-
- /* HKDF-Extract(<>, M.x) */
- os_memset(salt, 0, hash_len);
- if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
- k1, hash_len);
- return 0;
-}
-
-
-static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
- unsigned int hash_len)
-{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- const char *info = "second intermediate key";
- int res;
-
- /* k2 = HKDF(<>, "second intermediate key", N.x) */
-
- /* HKDF-Extract(<>, N.x) */
- os_memset(salt, 0, hash_len);
- res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
- if (res < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
- k2, hash_len);
- return 0;
-}
-
-
-static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
- unsigned int hash_len)
-{
- size_t nonce_len;
- u8 nonces[2 * DPP_MAX_NONCE_LEN];
- const char *info_ke = "DPP Key";
- u8 prk[DPP_MAX_HASH_LEN];
- int res;
- const u8 *addr[3];
- size_t len[3];
- size_t num_elem = 0;
-
- if (!auth->Mx_len || !auth->Nx_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Mx/Nx not available - cannot derive ke");
- return -1;
- }
-
- /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
-
- /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
- nonce_len = auth->curve->nonce_len;
- os_memcpy(nonces, auth->i_nonce, nonce_len);
- os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
- addr[num_elem] = auth->Mx;
- len[num_elem] = auth->Mx_len;
- num_elem++;
- addr[num_elem] = auth->Nx;
- len[num_elem] = auth->Nx_len;
- num_elem++;
- if (auth->peer_bi && auth->own_bi) {
- if (!auth->Lx_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Lx not available - cannot derive ke");
- return -1;
- }
- addr[num_elem] = auth->Lx;
- len[num_elem] = auth->secret_len;
- num_elem++;
- }
- res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
- num_elem, addr, len, prk);
- if (res < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
- ke, hash_len);
- return 0;
-}
-
-
-static void dpp_build_attr_status(struct wpabuf *msg,
- enum dpp_status_error status)
+void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
{
wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
wpabuf_put_le16(msg, DPP_ATTR_STATUS);
@@ -1642,8 +437,7 @@ static void dpp_build_attr_status(struct wpabuf *msg,
}
-static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
- const u8 *hash)
+void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
{
if (hash) {
wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
@@ -1654,372 +448,6 @@ static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
}
-static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
- const u8 *hash)
-{
- if (hash) {
- wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
- }
-}
-
-
-static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
- const struct wpabuf *pi,
- size_t nonce_len,
- const u8 *r_pubkey_hash,
- const u8 *i_pubkey_hash,
- unsigned int neg_freq)
-{
- struct wpabuf *msg;
- u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
- u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
- u8 *pos;
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end;
-
- /* Build DPP Authentication Request frame attributes */
- attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
- 4 + sizeof(wrapped_data);
- if (neg_freq > 0)
- attr_len += 4 + 2;
-#ifdef CONFIG_DPP2
- attr_len += 5;
-#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
- if (!msg)
- return NULL;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* Responder Bootstrapping Key Hash */
- dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
-
- /* Initiator Bootstrapping Key Hash */
- dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
-
- /* Initiator Protocol Key */
- if (pi) {
- wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pi));
- wpabuf_put_buf(msg, pi);
- }
-
- /* Channel */
- if (neg_freq > 0) {
- u8 op_class, channel;
-
- if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
- &channel) ==
- NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_INFO,
- "DPP: Unsupported negotiation frequency request: %d",
- neg_freq);
- wpabuf_free(msg);
- return NULL;
- }
- wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
- wpabuf_put_le16(msg, 2);
- wpabuf_put_u8(msg, op_class);
- wpabuf_put_u8(msg, channel);
- }
-
-#ifdef CONFIG_DPP2
- /* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
-#endif /* CONFIG_DPP2 */
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Wrapped data ({I-nonce, I-capabilities}k1) */
- pos = clear;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
- goto skip_i_nonce;
- }
- if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len - 1);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len - 1);
- pos += nonce_len - 1;
- goto skip_i_nonce;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len);
- pos += nonce_len;
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_i_nonce:
- if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
- goto skip_i_capab;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* I-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->i_capab = auth->allowed_roles;
- *pos++ = auth->i_capab;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
- wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
- pos[-1] = 0;
- }
-skip_i_capab:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- attr_end = wpabuf_put(msg, 0);
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0) {
- wpabuf_free(msg);
- return NULL;
- }
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Request frame attributes", msg);
-
- return msg;
-}
-
-
-static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
- enum dpp_status_error status,
- const struct wpabuf *pr,
- size_t nonce_len,
- const u8 *r_pubkey_hash,
- const u8 *i_pubkey_hash,
- const u8 *r_nonce, const u8 *i_nonce,
- const u8 *wrapped_r_auth,
- size_t wrapped_r_auth_len,
- const u8 *siv_key)
-{
- struct wpabuf *msg;
-#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
- 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
- u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
- u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end, *pos;
-
- auth->waiting_auth_conf = 1;
- auth->auth_resp_tries = 0;
-
- /* Build DPP Authentication Response frame attributes */
- attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
- 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
-#ifdef CONFIG_DPP2
- attr_len += 5;
-#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
- if (!msg)
- return NULL;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* DPP Status */
- if (status != 255)
- dpp_build_attr_status(msg, status);
-
- /* Responder Bootstrapping Key Hash */
- dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
-
- /* Initiator Bootstrapping Key Hash (mutual authentication) */
- dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
-
- /* Responder Protocol Key */
- if (pr) {
- wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pr));
- wpabuf_put_buf(msg, pr);
- }
-
-#ifdef CONFIG_DPP2
- /* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
-#endif /* CONFIG_DPP2 */
-
- attr_end = wpabuf_put(msg, 0);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
- pos = clear;
-
- if (r_nonce) {
- /* R-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, r_nonce, nonce_len);
- pos += nonce_len;
- }
-
- if (i_nonce) {
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, i_nonce, nonce_len);
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
- pos[nonce_len / 2] ^= 0x01;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- pos += nonce_len;
- }
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
- goto skip_r_capab;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* R-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
- DPP_CAPAB_ENROLLEE;
- *pos++ = auth->r_capab;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
- wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
- pos[-1] = 0;
- } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - incompatible R-capabilities");
- if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
- (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
- pos[-1] = 0;
- else
- pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
- DPP_CAPAB_CONFIGURATOR;
- }
-skip_r_capab:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (wrapped_r_auth) {
- /* {R-auth}ke */
- WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
- pos += 2;
- WPA_PUT_LE16(pos, wrapped_r_auth_len);
- pos += 2;
- os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
- pos += wrapped_r_auth_len;
- }
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0) {
- wpabuf_free(msg);
- return NULL;
- }
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Response frame attributes", msg);
- return msg;
-}
-
-
static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
u16 num_modes, unsigned int freq)
{
@@ -2138,14 +566,23 @@ static int dpp_channel_local_list(struct dpp_authentication *auth,
}
-static int dpp_prepare_channel_list(struct dpp_authentication *auth,
- struct hostapd_hw_modes *own_modes,
- u16 num_modes)
+int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes, u16 num_modes)
{
int res;
char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
unsigned int i;
+ if (!own_modes) {
+ if (!neg_freq)
+ return -1;
+ auth->num_freq = 1;
+ auth->freq[0] = neg_freq;
+ auth->curr_freq = neg_freq;
+ return 0;
+ }
+
if (auth->peer_bi->num_freq > 0)
res = dpp_channel_intersect(auth, own_modes, num_modes);
else
@@ -2178,183 +615,55 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth,
}
-static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
+int dpp_gen_uri(struct dpp_bootstrap_info *bi)
{
- struct dpp_bootstrap_info *bi;
- char *pk = NULL;
+ char macstr[ETH_ALEN * 2 + 10];
size_t len;
- if (auth->own_bi)
- return 0; /* already generated */
-
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- return -1;
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
- if (!pk)
- goto fail;
-
len = 4; /* "DPP:" */
- len += 4 + os_strlen(pk);
+ if (bi->chan)
+ len += 3 + os_strlen(bi->chan); /* C:...; */
+ if (is_zero_ether_addr(bi->mac_addr))
+ macstr[0] = '\0';
+ else
+ os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
+ MAC2STR(bi->mac_addr));
+ len += os_strlen(macstr); /* M:...; */
+ if (bi->info)
+ len += 3 + os_strlen(bi->info); /* I:...; */
+#ifdef CONFIG_DPP2
+ len += 4; /* V:2; */
+#endif /* CONFIG_DPP2 */
+ len += 4 + os_strlen(bi->pk); /* K:...;; */
+
+ os_free(bi->uri);
bi->uri = os_malloc(len + 1);
if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
- wpa_printf(MSG_DEBUG,
- "DPP: Auto-generated own bootstrapping key info: URI %s",
- bi->uri);
-
- auth->tmp_own_bi = auth->own_bi = bi;
-
- os_free(pk);
-
+ return -1;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;",
+ bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
+ bi->chan ? ";" : "",
+ macstr,
+ bi->info ? "I:" : "", bi->info ? bi->info : "",
+ bi->info ? ";" : "",
+ DPP_VERSION == 2 ? "V:2;" : "",
+ bi->pk);
return 0;
-fail:
- os_free(pk);
- dpp_bootstrap_info_free(bi);
- return -1;
}
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
- struct dpp_bootstrap_info *peer_bi,
- struct dpp_bootstrap_info *own_bi,
- u8 dpp_allowed_roles,
- unsigned int neg_freq,
- struct hostapd_hw_modes *own_modes,
- u16 num_modes)
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
{
struct dpp_authentication *auth;
- size_t nonce_len;
- size_t secret_len;
- struct wpabuf *pi = NULL;
- const u8 *r_pubkey_hash, *i_pubkey_hash;
-#ifdef CONFIG_TESTING_OPTIONS
- u8 test_hash[SHA256_MAC_LEN];
-#endif /* CONFIG_TESTING_OPTIONS */
auth = os_zalloc(sizeof(*auth));
if (!auth)
return NULL;
+ auth->global = dpp;
auth->msg_ctx = msg_ctx;
- auth->initiator = 1;
- auth->waiting_auth_resp = 1;
- auth->allowed_roles = dpp_allowed_roles;
- auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
- auth->peer_bi = peer_bi;
- auth->own_bi = own_bi;
- auth->curve = peer_bi->curve;
-
- if (dpp_autogen_bootstrap_key(auth) < 0 ||
- dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_nonce_override_len > 0) {
- wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
- nonce_len = dpp_nonce_override_len;
- os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
- } else {
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->i_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate I-nonce");
- goto fail;
- }
- }
-#else /* CONFIG_TESTING_OPTIONS */
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->i_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
- goto fail;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_protocol_key_override_len) {
- const struct dpp_curve_params *tmp_curve;
-
- wpa_printf(MSG_INFO,
- "DPP: TESTING - override protocol key");
- auth->own_protocol_key = dpp_set_keypair(
- &tmp_curve, dpp_protocol_key_override,
- dpp_protocol_key_override_len);
- } else {
- auth->own_protocol_key = dpp_gen_keypair(auth->curve);
- }
-#else /* CONFIG_TESTING_OPTIONS */
- auth->own_protocol_key = dpp_gen_keypair(auth->curve);
-#endif /* CONFIG_TESTING_OPTIONS */
- if (!auth->own_protocol_key)
- goto fail;
-
- pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- if (!pi)
- goto fail;
-
- /* ECDH: M = pI * BR */
- if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
- auth->Mx, &secret_len) < 0)
- goto fail;
- auth->secret_len = secret_len;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
- auth->Mx, auth->secret_len);
- auth->Mx_len = auth->secret_len;
-
- if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
- auth->curve->hash_len) < 0)
- goto fail;
-
- r_pubkey_hash = auth->peer_bi->pubkey_hash;
- i_pubkey_hash = auth->own_bi->pubkey_hash;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
- r_pubkey_hash = NULL;
- } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid R-Bootstrap Key Hash");
- os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- r_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
- i_pubkey_hash = NULL;
- } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid I-Bootstrap Key Hash");
- os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- i_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
- wpabuf_free(pi);
- pi = NULL;
- } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
- wpabuf_free(pi);
- pi = wpabuf_alloc(2 * auth->curve->prime_len);
- if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
- goto fail;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
- i_pubkey_hash, neg_freq);
- if (!auth->req_msg)
- goto fail;
-
-out:
- wpabuf_free(pi);
+ auth->conf_resp_status = 255;
return auth;
-fail:
- dpp_auth_deinit(auth);
- auth = NULL;
- goto out;
}
@@ -2376,7 +685,7 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
json_len = os_strlen(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
@@ -2463,7 +772,7 @@ fail:
}
-static void dpp_write_adv_proto(struct wpabuf *buf)
+void dpp_write_adv_proto(struct wpabuf *buf)
{
/* Advertisement Protocol IE */
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
@@ -2477,7 +786,7 @@ static void dpp_write_adv_proto(struct wpabuf *buf)
}
-static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
+void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
{
/* GAS Query */
wpabuf_put_le16(buf, wpabuf_len(query));
@@ -2512,1687 +821,80 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
}
-static void dpp_auth_success(struct dpp_authentication *auth)
-{
- wpa_printf(MSG_DEBUG,
- "DPP: Authentication success - clear temporary keys");
- os_memset(auth->Mx, 0, sizeof(auth->Mx));
- auth->Mx_len = 0;
- os_memset(auth->Nx, 0, sizeof(auth->Nx));
- auth->Nx_len = 0;
- os_memset(auth->Lx, 0, sizeof(auth->Lx));
- auth->Lx_len = 0;
- os_memset(auth->k1, 0, sizeof(auth->k1));
- os_memset(auth->k2, 0, sizeof(auth->k2));
-
- auth->auth_success = 1;
-}
-
-
-static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
-{
- struct wpabuf *pix, *prx, *bix, *brx;
- const u8 *addr[7];
- size_t len[7];
- size_t i, num_elem = 0;
- size_t nonce_len;
- u8 zero = 0;
- int res = -1;
-
- /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
- nonce_len = auth->curve->nonce_len;
-
- if (auth->initiator) {
- pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- if (auth->own_bi)
- bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
- else
- bix = NULL;
- brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
- } else {
- pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- if (auth->peer_bi)
- bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
- else
- bix = NULL;
- brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
- }
- if (!pix || !prx || !brx)
- goto fail;
-
- addr[num_elem] = auth->i_nonce;
- len[num_elem] = nonce_len;
- num_elem++;
-
- addr[num_elem] = auth->r_nonce;
- len[num_elem] = nonce_len;
- num_elem++;
-
- addr[num_elem] = wpabuf_head(pix);
- len[num_elem] = wpabuf_len(pix) / 2;
- num_elem++;
-
- addr[num_elem] = wpabuf_head(prx);
- len[num_elem] = wpabuf_len(prx) / 2;
- num_elem++;
-
- if (bix) {
- addr[num_elem] = wpabuf_head(bix);
- len[num_elem] = wpabuf_len(bix) / 2;
- num_elem++;
- }
-
- addr[num_elem] = wpabuf_head(brx);
- len[num_elem] = wpabuf_len(brx) / 2;
- num_elem++;
-
- addr[num_elem] = &zero;
- len[num_elem] = 1;
- num_elem++;
-
- wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
- for (i = 0; i < num_elem; i++)
- wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
- res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
- if (res == 0)
- wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
- auth->curve->hash_len);
-fail:
- wpabuf_free(pix);
- wpabuf_free(prx);
- wpabuf_free(bix);
- wpabuf_free(brx);
- return res;
-}
-
-
-static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
-{
- struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
- const u8 *addr[7];
- size_t len[7];
- size_t i, num_elem = 0;
- size_t nonce_len;
- u8 one = 1;
- int res = -1;
-
- /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
- nonce_len = auth->curve->nonce_len;
-
- if (auth->initiator) {
- pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- if (auth->own_bi)
- bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
- else
- bix = NULL;
- if (!auth->peer_bi)
- goto fail;
- brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
- } else {
- pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- if (auth->peer_bi)
- bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
- else
- bix = NULL;
- if (!auth->own_bi)
- goto fail;
- brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
- }
- if (!pix || !prx || !brx)
- goto fail;
-
- addr[num_elem] = auth->r_nonce;
- len[num_elem] = nonce_len;
- num_elem++;
-
- addr[num_elem] = auth->i_nonce;
- len[num_elem] = nonce_len;
- num_elem++;
-
- addr[num_elem] = wpabuf_head(prx);
- len[num_elem] = wpabuf_len(prx) / 2;
- num_elem++;
-
- addr[num_elem] = wpabuf_head(pix);
- len[num_elem] = wpabuf_len(pix) / 2;
- num_elem++;
-
- addr[num_elem] = wpabuf_head(brx);
- len[num_elem] = wpabuf_len(brx) / 2;
- num_elem++;
-
- if (bix) {
- addr[num_elem] = wpabuf_head(bix);
- len[num_elem] = wpabuf_len(bix) / 2;
- num_elem++;
- }
-
- addr[num_elem] = &one;
- len[num_elem] = 1;
- num_elem++;
-
- wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
- for (i = 0; i < num_elem; i++)
- wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
- res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
- if (res == 0)
- wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
- auth->curve->hash_len);
-fail:
- wpabuf_free(pix);
- wpabuf_free(prx);
- wpabuf_free(bix);
- wpabuf_free(brx);
- return res;
-}
-
-
-static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
-{
- const EC_GROUP *group;
- EC_POINT *l = NULL;
- EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
- const EC_POINT *BI_point;
- BN_CTX *bnctx;
- BIGNUM *lx, *sum, *q;
- const BIGNUM *bR_bn, *pR_bn;
- int ret = -1;
-
- /* L = ((bR + pR) modulo q) * BI */
-
- bnctx = BN_CTX_new();
- sum = BN_new();
- q = BN_new();
- lx = BN_new();
- if (!bnctx || !sum || !q || !lx)
- goto fail;
- BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
- if (!BI)
- goto fail;
- BI_point = EC_KEY_get0_public_key(BI);
- group = EC_KEY_get0_group(BI);
- if (!group)
- goto fail;
-
- bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
- pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
- if (!bR || !pR)
- goto fail;
- bR_bn = EC_KEY_get0_private_key(bR);
- pR_bn = EC_KEY_get0_private_key(pR);
- if (!bR_bn || !pR_bn)
- goto fail;
- if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
- BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
- goto fail;
- l = EC_POINT_new(group);
- if (!l ||
- EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
- bnctx) != 1) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
- goto fail;
- wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
- auth->Lx_len = auth->secret_len;
- ret = 0;
-fail:
- EC_POINT_clear_free(l);
- EC_KEY_free(BI);
- EC_KEY_free(bR);
- EC_KEY_free(pR);
- BN_clear_free(lx);
- BN_clear_free(sum);
- BN_free(q);
- BN_CTX_free(bnctx);
- return ret;
-}
-
-
-static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
-{
- const EC_GROUP *group;
- EC_POINT *l = NULL, *sum = NULL;
- EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
- const EC_POINT *BR_point, *PR_point;
- BN_CTX *bnctx;
- BIGNUM *lx;
- const BIGNUM *bI_bn;
- int ret = -1;
-
- /* L = bI * (BR + PR) */
-
- bnctx = BN_CTX_new();
- lx = BN_new();
- if (!bnctx || !lx)
- goto fail;
- BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
- PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
- if (!BR || !PR)
- goto fail;
- BR_point = EC_KEY_get0_public_key(BR);
- PR_point = EC_KEY_get0_public_key(PR);
-
- bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
- if (!bI)
- goto fail;
- group = EC_KEY_get0_group(bI);
- bI_bn = EC_KEY_get0_private_key(bI);
- if (!group || !bI_bn)
- goto fail;
- sum = EC_POINT_new(group);
- l = EC_POINT_new(group);
- if (!sum || !l ||
- EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
- EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
- bnctx) != 1) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
- goto fail;
- wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
- auth->Lx_len = auth->secret_len;
- ret = 0;
-fail:
- EC_POINT_clear_free(l);
- EC_POINT_clear_free(sum);
- EC_KEY_free(bI);
- EC_KEY_free(BR);
- EC_KEY_free(PR);
- BN_clear_free(lx);
- BN_CTX_free(bnctx);
- return ret;
-}
-
-
-static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
-{
- size_t nonce_len;
- size_t secret_len;
- struct wpabuf *msg, *pr = NULL;
- u8 r_auth[4 + DPP_MAX_HASH_LEN];
- u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
- size_t wrapped_r_auth_len;
- int ret = -1;
- const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
- enum dpp_status_error status = DPP_STATUS_OK;
-#ifdef CONFIG_TESTING_OPTIONS
- u8 test_hash[SHA256_MAC_LEN];
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
- if (!auth->own_bi)
- return -1;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_nonce_override_len > 0) {
- wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
- nonce_len = dpp_nonce_override_len;
- os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
- } else {
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->r_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate R-nonce");
- goto fail;
- }
- }
-#else /* CONFIG_TESTING_OPTIONS */
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->r_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
- goto fail;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
-
- EVP_PKEY_free(auth->own_protocol_key);
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_protocol_key_override_len) {
- const struct dpp_curve_params *tmp_curve;
-
- wpa_printf(MSG_INFO,
- "DPP: TESTING - override protocol key");
- auth->own_protocol_key = dpp_set_keypair(
- &tmp_curve, dpp_protocol_key_override,
- dpp_protocol_key_override_len);
- } else {
- auth->own_protocol_key = dpp_gen_keypair(auth->curve);
- }
-#else /* CONFIG_TESTING_OPTIONS */
- auth->own_protocol_key = dpp_gen_keypair(auth->curve);
-#endif /* CONFIG_TESTING_OPTIONS */
- if (!auth->own_protocol_key)
- goto fail;
-
- pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- if (!pr)
- goto fail;
-
- /* ECDH: N = pR * PI */
- if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
- auth->Nx, &secret_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
- auth->Nx, auth->secret_len);
- auth->Nx_len = auth->secret_len;
-
- if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
- auth->curve->hash_len) < 0)
- goto fail;
-
- if (auth->own_bi && auth->peer_bi) {
- /* Mutual authentication */
- if (dpp_auth_derive_l_responder(auth) < 0)
- goto fail;
- }
-
- if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
- goto fail;
-
- /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
- WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
- WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
- if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
- goto fail;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
- r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
- r_auth, 4 + auth->curve->hash_len,
- 0, NULL, NULL, wrapped_r_auth) < 0)
- goto fail;
- wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
- wrapped_r_auth, wrapped_r_auth_len);
- w_r_auth = wrapped_r_auth;
-
- r_pubkey_hash = auth->own_bi->pubkey_hash;
- if (auth->peer_bi)
- i_pubkey_hash = auth->peer_bi->pubkey_hash;
- else
- i_pubkey_hash = NULL;
-
- i_nonce = auth->i_nonce;
- r_nonce = auth->r_nonce;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
- r_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid R-Bootstrap Key Hash");
- os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- r_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
- i_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid I-Bootstrap Key Hash");
- if (i_pubkey_hash)
- os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
- else
- os_memset(test_hash, 0, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- i_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
- wpabuf_free(pr);
- pr = NULL;
- } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
- wpabuf_free(pr);
- pr = wpabuf_alloc(2 * auth->curve->prime_len);
- if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
- goto fail;
- } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
- w_r_auth = NULL;
- wrapped_r_auth_len = 0;
- } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
- status = 255;
- } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
- status = 254;
- } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
- r_nonce = NULL;
- } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
- i_nonce = NULL;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
- r_pubkey_hash, i_pubkey_hash,
- r_nonce, i_nonce,
- w_r_auth, wrapped_r_auth_len,
- auth->k2);
- if (!msg)
- goto fail;
- wpabuf_free(auth->resp_msg);
- auth->resp_msg = msg;
- ret = 0;
-fail:
- wpabuf_free(pr);
- return ret;
-}
-
-
-static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
- enum dpp_status_error status)
-{
- struct wpabuf *msg;
- const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
-#ifdef CONFIG_TESTING_OPTIONS
- u8 test_hash[SHA256_MAC_LEN];
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (!auth->own_bi)
- return -1;
- wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
-
- r_pubkey_hash = auth->own_bi->pubkey_hash;
- if (auth->peer_bi)
- i_pubkey_hash = auth->peer_bi->pubkey_hash;
- else
- i_pubkey_hash = NULL;
-
- i_nonce = auth->i_nonce;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
- r_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid R-Bootstrap Key Hash");
- os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- r_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
- i_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid I-Bootstrap Key Hash");
- if (i_pubkey_hash)
- os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
- else
- os_memset(test_hash, 0, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- i_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
- status = 255;
- } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
- i_nonce = NULL;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
- r_pubkey_hash, i_pubkey_hash,
- NULL, i_nonce, NULL, 0, auth->k1);
- if (!msg)
- return -1;
- wpabuf_free(auth->resp_msg);
- auth->resp_msg = msg;
- return 0;
-}
-
-
-struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
- struct dpp_bootstrap_info *peer_bi,
- struct dpp_bootstrap_info *own_bi,
- unsigned int freq, const u8 *hdr, const u8 *attr_start,
- size_t attr_len)
-{
- EVP_PKEY *pi = NULL;
- EVP_PKEY_CTX *ctx = NULL;
- size_t secret_len;
- const u8 *addr[2];
- size_t len[2];
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
- *channel;
- u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
- i_bootstrap_len, channel_len;
- struct dpp_authentication *auth = NULL;
-#ifdef CONFIG_DPP2
- const u8 *version;
- u16 version_len;
-#endif /* CONFIG_DPP2 */
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at Authentication Request");
- return NULL;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Missing or invalid required Wrapped Data attribute");
- return NULL;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
- wrapped_data, wrapped_data_len);
- attr_len = wrapped_data - 4 - attr_start;
-
- auth = os_zalloc(sizeof(*auth));
- if (!auth)
- goto fail;
- auth->msg_ctx = msg_ctx;
- auth->peer_bi = peer_bi;
- auth->own_bi = own_bi;
- auth->curve = own_bi->curve;
- auth->curr_freq = freq;
-
- auth->peer_version = 1; /* default to the first version */
-#ifdef CONFIG_DPP2
- version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
- &version_len);
- if (version) {
- if (version_len < 1 || version[0] == 0) {
- dpp_auth_fail(auth,
- "Invalid Protocol Version attribute");
- goto fail;
- }
- auth->peer_version = version[0];
- wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
- auth->peer_version);
- }
-#endif /* CONFIG_DPP2 */
-
- channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
- &channel_len);
- if (channel) {
- int neg_freq;
-
- if (channel_len < 2) {
- dpp_auth_fail(auth, "Too short Channel attribute");
- goto fail;
- }
-
- neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
- wpa_printf(MSG_DEBUG,
- "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
- channel[0], channel[1], neg_freq);
- if (neg_freq < 0) {
- dpp_auth_fail(auth,
- "Unsupported Channel attribute value");
- goto fail;
- }
-
- if (auth->curr_freq != (unsigned int) neg_freq) {
- wpa_printf(MSG_DEBUG,
- "DPP: Changing negotiation channel from %u MHz to %u MHz",
- freq, neg_freq);
- auth->curr_freq = neg_freq;
- }
- }
-
- i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
- &i_proto_len);
- if (!i_proto) {
- dpp_auth_fail(auth,
- "Missing required Initiator Protocol Key attribute");
- goto fail;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
- i_proto, i_proto_len);
-
- /* M = bR * PI */
- pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
- if (!pi) {
- dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
- goto fail;
- }
- dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
-
- if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
- goto fail;
- auth->secret_len = secret_len;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
- auth->Mx, auth->secret_len);
- auth->Mx_len = auth->secret_len;
-
- if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
- auth->curve->hash_len) < 0)
- goto fail;
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- addr[1] = attr_start;
- len[1] = attr_len;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- goto fail;
- if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
- os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
-
- i_capab = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_I_CAPABILITIES,
- &i_capab_len);
- if (!i_capab || i_capab_len < 1) {
- dpp_auth_fail(auth, "Missing or invalid I-capabilities");
- goto fail;
- }
- auth->i_capab = i_capab[0];
- wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
-
- bin_clear_free(unwrapped, unwrapped_len);
- unwrapped = NULL;
-
- switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
- case DPP_CAPAB_ENROLLEE:
- if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Local policy does not allow Configurator role");
- goto not_compatible;
- }
- wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
- auth->configurator = 1;
- break;
- case DPP_CAPAB_CONFIGURATOR:
- if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Local policy does not allow Enrollee role");
- goto not_compatible;
- }
- wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
- auth->configurator = 0;
- break;
- case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
- if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
- wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
- auth->configurator = 0;
- } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
- wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
- auth->configurator = 1;
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Local policy does not allow Configurator/Enrollee role");
- goto not_compatible;
- }
- break;
- default:
- wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
- wpa_msg(auth->msg_ctx, MSG_INFO,
- DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
- auth->i_capab & DPP_CAPAB_ROLE_MASK);
- goto fail;
- }
-
- auth->peer_protocol_key = pi;
- pi = NULL;
- if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
- char hex[SHA256_MAC_LEN * 2 + 1];
-
- wpa_printf(MSG_DEBUG,
- "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
- if (dpp_auth_build_resp_status(auth,
- DPP_STATUS_RESPONSE_PENDING) < 0)
- goto fail;
- i_bootstrap = dpp_get_attr(attr_start, attr_len,
- DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
- &i_bootstrap_len);
- if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
- auth->response_pending = 1;
- os_memcpy(auth->waiting_pubkey_hash,
- i_bootstrap, i_bootstrap_len);
- wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
- i_bootstrap_len);
- } else {
- hex[0] = '\0';
- }
-
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
- "%s", hex);
- return auth;
- }
- if (dpp_auth_build_resp_ok(auth) < 0)
- goto fail;
-
- return auth;
-
-not_compatible:
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
- "i-capab=0x%02x", auth->i_capab);
- if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
- auth->configurator = 1;
- else
- auth->configurator = 0;
- auth->peer_protocol_key = pi;
- pi = NULL;
- if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
- goto fail;
-
- auth->remove_on_tx_status = 1;
- return auth;
-fail:
- bin_clear_free(unwrapped, unwrapped_len);
- EVP_PKEY_free(pi);
- EVP_PKEY_CTX_free(ctx);
- dpp_auth_deinit(auth);
- return NULL;
-}
-
-
-int dpp_notify_new_qr_code(struct dpp_authentication *auth,
- struct dpp_bootstrap_info *peer_bi)
-{
- if (!auth || !auth->response_pending ||
- os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
- SHA256_MAC_LEN) != 0)
- return 0;
-
- wpa_printf(MSG_DEBUG,
- "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
- MACSTR, MAC2STR(auth->peer_mac_addr));
- auth->peer_bi = peer_bi;
-
- if (dpp_auth_build_resp_ok(auth) < 0)
- return -1;
-
- return 1;
-}
-
-
-static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
- enum dpp_status_error status)
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name,
+ enum dpp_netrole netrole,
+ const char *mud_url, int *opclasses)
{
- struct wpabuf *msg;
- u8 i_auth[4 + DPP_MAX_HASH_LEN];
- size_t i_auth_len;
- u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
- size_t r_nonce_len;
- const u8 *addr[2];
- size_t len[2], attr_len;
- u8 *wrapped_i_auth;
- u8 *wrapped_r_nonce;
- u8 *attr_start, *attr_end;
- const u8 *r_pubkey_hash, *i_pubkey_hash;
-#ifdef CONFIG_TESTING_OPTIONS
- u8 test_hash[SHA256_MAC_LEN];
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
-
- i_auth_len = 4 + auth->curve->hash_len;
- r_nonce_len = 4 + auth->curve->nonce_len;
- /* Build DPP Authentication Confirmation frame attributes */
- attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
- 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
- if (!msg)
- goto fail;
-
- attr_start = wpabuf_put(msg, 0);
-
- r_pubkey_hash = auth->peer_bi->pubkey_hash;
- if (auth->own_bi)
- i_pubkey_hash = auth->own_bi->pubkey_hash;
- else
- i_pubkey_hash = NULL;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
- goto skip_status;
- } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
- status = 254;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* DPP Status */
- dpp_build_attr_status(msg, status);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_status:
- if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
- r_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid R-Bootstrap Key Hash");
- os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- r_pubkey_hash = test_hash;
- } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
- i_pubkey_hash = NULL;
- } else if (dpp_test ==
- DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - invalid I-Bootstrap Key Hash");
- if (i_pubkey_hash)
- os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
- else
- os_memset(test_hash, 0, SHA256_MAC_LEN);
- test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
- i_pubkey_hash = test_hash;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Responder Bootstrapping Key Hash */
- dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
-
- /* Initiator Bootstrapping Key Hash (mutual authentication) */
- dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
- goto skip_wrapped_data;
- if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
- i_auth_len = 0;
-#endif /* CONFIG_TESTING_OPTIONS */
-
- attr_end = wpabuf_put(msg, 0);
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- if (status == DPP_STATUS_OK) {
- /* I-auth wrapped with ke */
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
- wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
- goto skip_i_auth;
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
- * 1) */
- WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
- WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
- if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
- goto fail;
+ size_t len, name_len;
+ const char *tech = "infra";
+ const char *dpp_name;
+ struct wpabuf *buf, *json;
+ char *csr = NULL;
#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
- i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
- }
-skip_i_auth:
-#endif /* CONFIG_TESTING_OPTIONS */
- if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
- i_auth, i_auth_len,
- 2, addr, len, wrapped_i_auth) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
- wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
- } else {
- /* R-nonce wrapped with k2 */
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
- wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
-
- WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
- WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
- os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
-
- if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
- r_nonce, r_nonce_len,
- 2, addr, len, wrapped_r_nonce) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
- wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
- }
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ static const char *bogus_tech = "knfra";
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ tech = bogus_tech;
}
-skip_wrapped_data:
#endif /* CONFIG_TESTING_OPTIONS */
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Confirmation frame attributes",
- msg);
- if (status == DPP_STATUS_OK)
- dpp_auth_success(auth);
-
- return msg;
-
-fail:
- wpabuf_free(msg);
- return NULL;
-}
-
+ dpp_name = name ? name : "Test";
+ name_len = os_strlen(dpp_name);
-static void
-dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
- const u8 *attr_start, size_t attr_len,
- const u8 *wrapped_data, u16 wrapped_data_len,
- enum dpp_status_error status)
-{
- const u8 *addr[2];
- size_t len[2];
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- const u8 *i_nonce, *r_capab;
- u16 i_nonce_len, r_capab_len;
-
- if (status == DPP_STATUS_NOT_COMPATIBLE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Responder reported incompatible roles");
- } else if (status == DPP_STATUS_RESPONSE_PENDING) {
- wpa_printf(MSG_DEBUG,
- "DPP: Responder reported more time needed");
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Responder reported failure (status %d)",
- status);
- dpp_auth_fail(auth, "Responder reported failure");
- return;
- }
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- addr[1] = attr_start;
- len[1] = attr_len;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- goto fail;
- if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
- if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "I-nonce mismatch");
- goto fail;
- }
-
- r_capab = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_R_CAPABILITIES,
- &r_capab_len);
- if (!r_capab || r_capab_len < 1) {
- dpp_auth_fail(auth, "Missing or invalid R-capabilities");
- goto fail;
- }
- auth->r_capab = r_capab[0];
- wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
- if (status == DPP_STATUS_NOT_COMPATIBLE) {
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
- "r-capab=0x%02x", auth->r_capab);
- } else if (status == DPP_STATUS_RESPONSE_PENDING) {
- u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
-
- if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
- (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
- wpa_msg(auth->msg_ctx, MSG_INFO,
- DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
- role);
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Continue waiting for full DPP Authentication Response");
- wpa_msg(auth->msg_ctx, MSG_INFO,
- DPP_EVENT_RESPONSE_PENDING "%s",
- auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
- }
- }
-fail:
- bin_clear_free(unwrapped, unwrapped_len);
-}
-
-
-struct wpabuf *
-dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
- const u8 *attr_start, size_t attr_len)
-{
- EVP_PKEY *pr;
- size_t secret_len;
- const u8 *addr[2];
- size_t len[2];
- u8 *unwrapped = NULL, *unwrapped2 = NULL;
- size_t unwrapped_len = 0, unwrapped2_len = 0;
- const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
- *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
- u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
- r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
- wrapped2_len, r_auth_len;
- u8 r_auth2[DPP_MAX_HASH_LEN];
- u8 role;
+ len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
+ if (mud_url && mud_url[0])
+ len += 10 + os_strlen(mud_url);
#ifdef CONFIG_DPP2
- const u8 *version;
- u16 version_len;
-#endif /* CONFIG_DPP2 */
+ if (auth->csr) {
+ size_t csr_len;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at Authentication Response");
- return NULL;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (!auth->initiator || !auth->peer_bi) {
- dpp_auth_fail(auth, "Unexpected Authentication Response");
- return NULL;
- }
-
- auth->waiting_auth_resp = 0;
-
- wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- dpp_auth_fail(auth,
- "Missing or invalid required Wrapped Data attribute");
- return NULL;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
- wrapped_data, wrapped_data_len);
-
- attr_len = wrapped_data - 4 - attr_start;
-
- r_bootstrap = dpp_get_attr(attr_start, attr_len,
- DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
- &r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- dpp_auth_fail(auth,
- "Missing or invalid required Responder Bootstrapping Key Hash attribute");
- return NULL;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
- r_bootstrap, r_bootstrap_len);
- if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
- SHA256_MAC_LEN) != 0) {
- dpp_auth_fail(auth,
- "Unexpected Responder Bootstrapping Key Hash value");
- wpa_hexdump(MSG_DEBUG,
- "DPP: Expected Responder Bootstrapping Key Hash",
- auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
- return NULL;
- }
-
- i_bootstrap = dpp_get_attr(attr_start, attr_len,
- DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
- &i_bootstrap_len);
- if (i_bootstrap) {
- if (i_bootstrap_len != SHA256_MAC_LEN) {
- dpp_auth_fail(auth,
- "Invalid Initiator Bootstrapping Key Hash attribute");
- return NULL;
- }
- wpa_hexdump(MSG_MSGDUMP,
- "DPP: Initiator Bootstrapping Key Hash",
- i_bootstrap, i_bootstrap_len);
- if (!auth->own_bi ||
- os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
- SHA256_MAC_LEN) != 0) {
- dpp_auth_fail(auth,
- "Initiator Bootstrapping Key Hash attribute did not match");
- return NULL;
- }
- } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
- /* PKEX bootstrapping mandates use of mutual authentication */
- dpp_auth_fail(auth,
- "Missing Initiator Bootstrapping Key Hash attribute");
- return NULL;
- }
-
- auth->peer_version = 1; /* default to the first version */
-#ifdef CONFIG_DPP2
- version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
- &version_len);
- if (version) {
- if (version_len < 1 || version[0] == 0) {
- dpp_auth_fail(auth,
- "Invalid Protocol Version attribute");
+ csr = base64_encode_no_lf(wpabuf_head(auth->csr),
+ wpabuf_len(auth->csr), &csr_len);
+ if (!csr)
return NULL;
- }
- auth->peer_version = version[0];
- wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
- auth->peer_version);
+ len += 30 + csr_len;
}
#endif /* CONFIG_DPP2 */
-
- status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
- &status_len);
- if (!status || status_len < 1) {
- dpp_auth_fail(auth,
- "Missing or invalid required DPP Status attribute");
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
- auth->auth_resp_status = status[0];
- if (status[0] != DPP_STATUS_OK) {
- dpp_auth_resp_rx_status(auth, hdr, attr_start,
- attr_len, wrapped_data,
- wrapped_data_len, status[0]);
+ json = wpabuf_alloc(len);
+ if (!json)
return NULL;
- }
-
- if (!i_bootstrap && auth->own_bi) {
- wpa_printf(MSG_DEBUG,
- "DPP: Responder decided not to use mutual authentication");
- auth->own_bi = NULL;
- }
-
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
- auth->own_bi != NULL);
- r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
- &r_proto_len);
- if (!r_proto) {
- dpp_auth_fail(auth,
- "Missing required Responder Protocol Key attribute");
- return NULL;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
- r_proto, r_proto_len);
-
- /* N = pI * PR */
- pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
- if (!pr) {
- dpp_auth_fail(auth, "Invalid Responder Protocol Key");
+ json_start_object(json, NULL);
+ if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
+ wpabuf_free(json);
return NULL;
}
- dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
-
- if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
- dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
- goto fail;
- }
- EVP_PKEY_free(auth->peer_protocol_key);
- auth->peer_protocol_key = pr;
- pr = NULL;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
- auth->Nx, auth->secret_len);
- auth->Nx_len = auth->secret_len;
-
- if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
- auth->curve->hash_len) < 0)
- goto fail;
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- addr[1] = attr_start;
- len[1] = attr_len;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- goto fail;
- if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
- os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
-
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
- if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "I-nonce mismatch");
- goto fail;
+ json_value_sep(json);
+ json_add_string(json, "wi-fi_tech", tech);
+ json_value_sep(json);
+ json_add_string(json, "netRole", dpp_netrole_str(netrole));
+ if (mud_url && mud_url[0]) {
+ json_value_sep(json);
+ json_add_string(json, "mudurl", mud_url);
}
+ if (opclasses) {
+ int i;
- if (auth->own_bi) {
- /* Mutual authentication */
- if (dpp_auth_derive_l_initiator(auth) < 0)
- goto fail;
- }
-
- r_capab = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_R_CAPABILITIES,
- &r_capab_len);
- if (!r_capab || r_capab_len < 1) {
- dpp_auth_fail(auth, "Missing or invalid R-capabilities");
- goto fail;
- }
- auth->r_capab = r_capab[0];
- wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
- role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
- if ((auth->allowed_roles ==
- (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
- (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
- /* Peer selected its role, so move from "either role" to the
- * role that is compatible with peer's selection. */
- auth->configurator = role == DPP_CAPAB_ENROLLEE;
- wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
- auth->configurator ? "Configurator" : "Enrollee");
- } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
- (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
- wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Unexpected role in R-capabilities 0x%02x",
- role);
- if (role != DPP_CAPAB_ENROLLEE &&
- role != DPP_CAPAB_CONFIGURATOR)
- goto fail;
- bin_clear_free(unwrapped, unwrapped_len);
- auth->remove_on_tx_status = 1;
- return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
+ json_value_sep(json);
+ json_start_array(json, "bandSupport");
+ for (i = 0; opclasses[i]; i++)
+ wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
+ json_end_array(json);
}
-
- wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
- if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
- dpp_auth_fail(auth,
- "Missing or invalid Secondary Wrapped Data");
- goto fail;
+ if (csr) {
+ json_value_sep(json);
+ json_add_string(json, "pkcs10", csr);
}
+ json_end_object(json);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped2, wrapped2_len);
-
- if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
- goto fail;
+ buf = dpp_build_conf_req(auth, wpabuf_head(json));
+ wpabuf_free(json);
+ os_free(csr);
- unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
- unwrapped2 = os_malloc(unwrapped2_len);
- if (!unwrapped2)
- goto fail;
- if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
- wrapped2, wrapped2_len,
- 0, NULL, NULL, unwrapped2) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped2, unwrapped2_len);
-
- if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
- dpp_auth_fail(auth,
- "Invalid attribute in secondary unwrapped data");
- goto fail;
- }
-
- r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
- &r_auth_len);
- if (!r_auth || r_auth_len != auth->curve->hash_len) {
- dpp_auth_fail(auth,
- "Missing or invalid Responder Authenticating Tag");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
- r_auth, r_auth_len);
- /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
- if (dpp_gen_r_auth(auth, r_auth2) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
- r_auth2, r_auth_len);
- if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
- dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
- bin_clear_free(unwrapped, unwrapped_len);
- bin_clear_free(unwrapped2, unwrapped2_len);
- auth->remove_on_tx_status = 1;
- return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
- }
-
- bin_clear_free(unwrapped, unwrapped_len);
- bin_clear_free(unwrapped2, unwrapped2_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - Authentication Response in place of Confirm");
- if (dpp_auth_build_resp_ok(auth) < 0)
- return NULL;
- return wpabuf_dup(auth->resp_msg);
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- return dpp_auth_build_conf(auth, DPP_STATUS_OK);
-
-fail:
- bin_clear_free(unwrapped, unwrapped_len);
- bin_clear_free(unwrapped2, unwrapped2_len);
- EVP_PKEY_free(pr);
- return NULL;
-}
-
-
-static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
- const u8 *hdr,
- const u8 *attr_start, size_t attr_len,
- const u8 *wrapped_data,
- u16 wrapped_data_len,
- enum dpp_status_error status)
-{
- const u8 *addr[2];
- size_t len[2];
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- const u8 *r_nonce;
- u16 r_nonce_len;
-
- /* Authentication Confirm failure cases are expected to include
- * {R-nonce}k2 in the Wrapped Data attribute. */
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- addr[1] = attr_start;
- len[1] = attr_len;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped) {
- dpp_auth_fail(auth, "Authentication failed");
- goto fail;
- }
- if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
- goto fail;
- }
- if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
- wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
- r_nonce, r_nonce_len);
- wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
- auth->r_nonce, r_nonce_len);
- dpp_auth_fail(auth, "R-nonce mismatch");
- goto fail;
- }
-
- if (status == DPP_STATUS_NOT_COMPATIBLE)
- dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
- else if (status == DPP_STATUS_AUTH_FAILURE)
- dpp_auth_fail(auth, "Peer reported authentication failure)");
-
-fail:
- bin_clear_free(unwrapped, unwrapped_len);
- return -1;
-}
-
-
-int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
- const u8 *attr_start, size_t attr_len)
-{
- const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
- u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
- i_auth_len;
- const u8 *addr[2];
- size_t len[2];
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- u8 i_auth2[DPP_MAX_HASH_LEN];
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at Authentication Confirm");
- return -1;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (auth->initiator || !auth->own_bi) {
- dpp_auth_fail(auth, "Unexpected Authentication Confirm");
- return -1;
- }
-
- auth->waiting_auth_conf = 0;
-
- wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- dpp_auth_fail(auth,
- "Missing or invalid required Wrapped Data attribute");
- return -1;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
- wrapped_data, wrapped_data_len);
-
- attr_len = wrapped_data - 4 - attr_start;
-
- r_bootstrap = dpp_get_attr(attr_start, attr_len,
- DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
- &r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- dpp_auth_fail(auth,
- "Missing or invalid required Responder Bootstrapping Key Hash attribute");
- return -1;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
- r_bootstrap, r_bootstrap_len);
- if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
- SHA256_MAC_LEN) != 0) {
- wpa_hexdump(MSG_DEBUG,
- "DPP: Expected Responder Bootstrapping Key Hash",
- auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
- dpp_auth_fail(auth,
- "Responder Bootstrapping Key Hash mismatch");
- return -1;
- }
-
- i_bootstrap = dpp_get_attr(attr_start, attr_len,
- DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
- &i_bootstrap_len);
- if (i_bootstrap) {
- if (i_bootstrap_len != SHA256_MAC_LEN) {
- dpp_auth_fail(auth,
- "Invalid Initiator Bootstrapping Key Hash attribute");
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP,
- "DPP: Initiator Bootstrapping Key Hash",
- i_bootstrap, i_bootstrap_len);
- if (!auth->peer_bi ||
- os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
- SHA256_MAC_LEN) != 0) {
- dpp_auth_fail(auth,
- "Initiator Bootstrapping Key Hash mismatch");
- return -1;
- }
- } else if (auth->peer_bi) {
- /* Mutual authentication and peer did not include its
- * Bootstrapping Key Hash attribute. */
- dpp_auth_fail(auth,
- "Missing Initiator Bootstrapping Key Hash attribute");
- return -1;
- }
-
- status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
- &status_len);
- if (!status || status_len < 1) {
- dpp_auth_fail(auth,
- "Missing or invalid required DPP Status attribute");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
- if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
- status[0] == DPP_STATUS_AUTH_FAILURE)
- return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
- attr_len, wrapped_data,
- wrapped_data_len, status[0]);
-
- if (status[0] != DPP_STATUS_OK) {
- dpp_auth_fail(auth, "Authentication failed");
- return -1;
- }
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- addr[1] = attr_start;
- len[1] = attr_len;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- return -1;
- if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_auth_fail(auth, "AES-SIV decryption failed");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
- &i_auth_len);
- if (!i_auth || i_auth_len != auth->curve->hash_len) {
- dpp_auth_fail(auth,
- "Missing or invalid Initiator Authenticating Tag");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
- i_auth, i_auth_len);
- /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
- if (dpp_gen_i_auth(auth, i_auth2) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
- i_auth2, i_auth_len);
- if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
- dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
- goto fail;
- }
-
- bin_clear_free(unwrapped, unwrapped_len);
- dpp_auth_success(auth);
- return 0;
-fail:
- bin_clear_free(unwrapped, unwrapped_len);
- return -1;
+ return buf;
}
@@ -4233,6 +935,8 @@ struct dpp_configuration * dpp_configuration_alloc(const char *type)
conf->akm = DPP_AKM_PSK_SAE_DPP;
else if (bin_str_eq(type, len, "dpp"))
conf->akm = DPP_AKM_DPP;
+ else if (bin_str_eq(type, len, "dot1x"))
+ conf->akm = DPP_AKM_DOT1X;
else
goto fail;
@@ -4295,22 +999,25 @@ void dpp_configuration_free(struct dpp_configuration *conf)
return;
str_clear_free(conf->passphrase);
os_free(conf->group_id);
+ os_free(conf->csrattrs);
bin_clear_free(conf, sizeof(*conf));
}
-static int dpp_configuration_parse(struct dpp_authentication *auth,
- const char *cmd)
+static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
+ const char *cmd, int idx)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
struct dpp_configuration *conf = NULL;
+ size_t len;
pos = os_strstr(cmd, " conf=sta-");
if (pos) {
conf_sta = dpp_configuration_alloc(pos + 10);
if (!conf_sta)
goto fail;
+ conf_sta->netrole = DPP_NETROLE_STA;
conf = conf_sta;
}
@@ -4319,9 +1026,14 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
conf_ap = dpp_configuration_alloc(pos + 9);
if (!conf_ap)
goto fail;
+ conf_ap->netrole = DPP_NETROLE_AP;
conf = conf_ap;
}
+ pos = os_strstr(cmd, " conf=configurator");
+ if (pos)
+ auth->provision_configurator = 1;
+
if (!conf)
return 0;
@@ -4344,6 +1056,16 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
#endif /* CONFIG_TESTING_OPTIONS */
}
+ pos = os_strstr(cmd, " ssid_charset=");
+ if (pos) {
+ if (conf_ap) {
+ wpa_printf(MSG_INFO,
+ "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
+ goto fail;
+ }
+ conf->ssid_charset = atoi(pos + 14);
+ }
+
pos = os_strstr(cmd, " pass=");
if (pos) {
size_t pass_len;
@@ -4393,11 +1115,29 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
conf->netaccesskey_expiry = val;
}
+ pos = os_strstr(cmd, " csrattrs=");
+ if (pos) {
+ pos += 10;
+ end = os_strchr(pos, ' ');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->csrattrs = os_zalloc(len + 1);
+ if (!conf->csrattrs)
+ goto fail;
+ os_memcpy(conf->csrattrs, pos, len);
+ }
+
if (!dpp_configuration_valid(conf))
goto fail;
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
+ if (idx == 0) {
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ } else if (idx == 1) {
+ auth->conf2_sta = conf_sta;
+ auth->conf2_ap = conf_ap;
+ } else {
+ goto fail;
+ }
return 0;
fail:
@@ -4407,6 +1147,41 @@ fail:
}
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+ char *tmp;
+ size_t len;
+ int res;
+
+ pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
+ if (!pos)
+ return dpp_configuration_parse_helper(auth, cmd, 0);
+
+ len = pos - cmd;
+ tmp = os_malloc(len + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, cmd, len);
+ tmp[len] = '\0';
+ res = dpp_configuration_parse_helper(auth, cmd, 0);
+ str_clear_free(tmp);
+ if (res)
+ goto fail;
+ res = dpp_configuration_parse_helper(auth, cmd + len, 1);
+ if (res)
+ goto fail;
+ return 0;
+fail:
+ dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
+ dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
+ return -1;
+}
+
+
static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
{
@@ -4424,52 +1199,110 @@ dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
}
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_authentication *auth,
- const char *cmd)
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
{
const char *pos;
+ char *tmp = NULL;
+ int ret = -1;
- if (!cmd)
+ if (!cmd || auth->configurator_set)
return 0;
+ auth->configurator_set = 1;
+
+ if (cmd[0] != ' ') {
+ size_t len;
+
+ len = os_strlen(cmd);
+ tmp = os_malloc(len + 2);
+ if (!tmp)
+ goto fail;
+ tmp[0] = ' ';
+ os_memcpy(tmp + 1, cmd, len + 1);
+ cmd = tmp;
+ }
wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
pos = os_strstr(cmd, " configurator=");
- if (pos) {
+ if (!auth->conf && pos) {
pos += 14;
- auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
+ auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
if (!auth->conf) {
wpa_printf(MSG_INFO,
"DPP: Could not find the specified configurator");
- return -1;
+ goto fail;
}
}
+ pos = os_strstr(cmd, " conn_status=");
+ if (pos) {
+ pos += 13;
+ auth->send_conn_status = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " akm_use_selector=");
+ if (pos) {
+ pos += 18;
+ auth->akm_use_selector = atoi(pos);
+ }
+
if (dpp_configuration_parse(auth, cmd) < 0) {
- wpa_msg(msg_ctx, MSG_INFO,
+ wpa_msg(auth->msg_ctx, MSG_INFO,
"DPP: Failed to set configurator parameters");
- return -1;
+ goto fail;
}
- return 0;
+ ret = 0;
+fail:
+ os_free(tmp);
+ return ret;
}
void dpp_auth_deinit(struct dpp_authentication *auth)
{
+ unsigned int i;
+
if (!auth)
return;
dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
EVP_PKEY_free(auth->own_protocol_key);
EVP_PKEY_free(auth->peer_protocol_key);
+ EVP_PKEY_free(auth->reconfig_old_protocol_key);
wpabuf_free(auth->req_msg);
wpabuf_free(auth->resp_msg);
wpabuf_free(auth->conf_req);
- os_free(auth->connector);
+ wpabuf_free(auth->reconfig_req_msg);
+ wpabuf_free(auth->reconfig_resp_msg);
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ struct dpp_config_obj *conf = &auth->conf_obj[i];
+
+ os_free(conf->connector);
+ wpabuf_free(conf->c_sign_key);
+ wpabuf_free(conf->certbag);
+ wpabuf_free(conf->certs);
+ wpabuf_free(conf->cacert);
+ os_free(conf->server_name);
+ wpabuf_free(conf->pp_key);
+ }
+#ifdef CONFIG_DPP2
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
+ os_free(auth->csrattrs);
+ wpabuf_free(auth->csr);
+ wpabuf_free(auth->priv_key);
+ wpabuf_free(auth->cacert);
+ wpabuf_free(auth->certbag);
+ os_free(auth->trusted_eap_server_name);
+ wpabuf_free(auth->conf_resp_tcp);
+#endif /* CONFIG_DPP2 */
wpabuf_free(auth->net_access_key);
- wpabuf_free(auth->c_sign_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
+ if (auth->tmp_peer_bi) {
+ dl_list_del(&auth->tmp_peer_bi->list);
+ dpp_bootstrap_info_free(auth->tmp_peer_bi);
+ }
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
os_free(auth->discovery_override);
@@ -4484,7 +1317,6 @@ dpp_build_conf_start(struct dpp_authentication *auth,
struct dpp_configuration *conf, size_t tailroom)
{
struct wpabuf *buf;
- char ssid[6 * sizeof(conf->ssid) + 1];
#ifdef CONFIG_TESTING_OPTIONS
if (auth->discovery_override)
@@ -4494,62 +1326,71 @@ dpp_build_conf_start(struct dpp_authentication *auth,
buf = wpabuf_alloc(200 + tailroom);
if (!buf)
return NULL;
- wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
+ json_start_object(buf, NULL);
+ json_add_string(buf, "wi-fi_tech", "infra");
+ json_value_sep(buf);
#ifdef CONFIG_TESTING_OPTIONS
if (auth->discovery_override) {
wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
auth->discovery_override);
+ wpabuf_put_str(buf, "\"discovery\":");
wpabuf_put_str(buf, auth->discovery_override);
- wpabuf_put_u8(buf, ',');
+ json_value_sep(buf);
return buf;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpabuf_put_str(buf, "{\"ssid\":\"");
- json_escape_string(ssid, sizeof(ssid),
- (const char *) conf->ssid, conf->ssid_len);
- wpabuf_put_str(buf, ssid);
- wpabuf_put_str(buf, "\"},");
+ json_start_object(buf, "discovery");
+ if (((!conf->ssid_charset || auth->peer_version < 2) &&
+ json_add_string_escape(buf, "ssid", conf->ssid,
+ conf->ssid_len) < 0) ||
+ ((conf->ssid_charset && auth->peer_version >= 2) &&
+ json_add_base64url(buf, "ssid64", conf->ssid,
+ conf->ssid_len) < 0)) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ if (conf->ssid_charset > 0) {
+ json_value_sep(buf);
+ json_add_int(buf, "ssid_charset", conf->ssid_charset);
+ }
+ json_end_object(buf);
+ json_value_sep(buf);
return buf;
}
-static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
- const char *kid, const struct dpp_curve_params *curve)
+int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
+ const char *kid, const struct dpp_curve_params *curve)
{
struct wpabuf *pub;
const u8 *pos;
- char *x = NULL, *y = NULL;
int ret = -1;
pub = dpp_get_pubkey_point(key, 0);
if (!pub)
goto fail;
+
+ json_start_object(buf, name);
+ json_add_string(buf, "kty", "EC");
+ json_value_sep(buf);
+ json_add_string(buf, "crv", curve->jwk_crv);
+ json_value_sep(buf);
pos = wpabuf_head(pub);
- x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
+ if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
+ goto fail;
+ json_value_sep(buf);
pos += curve->prime_len;
- y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
- if (!x || !y)
+ if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
goto fail;
-
- wpabuf_put_str(buf, "\"");
- wpabuf_put_str(buf, name);
- wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
- wpabuf_put_str(buf, curve->jwk_crv);
- wpabuf_put_str(buf, "\",\"x\":\"");
- wpabuf_put_str(buf, x);
- wpabuf_put_str(buf, "\",\"y\":\"");
- wpabuf_put_str(buf, y);
if (kid) {
- wpabuf_put_str(buf, "\",\"kid\":\"");
- wpabuf_put_str(buf, kid);
+ json_value_sep(buf);
+ json_add_string(buf, "kid", kid);
}
- wpabuf_put_str(buf, "\"}");
+ json_end_object(buf);
ret = 0;
fail:
wpabuf_free(pub);
- os_free(x);
- os_free(y);
return ret;
}
@@ -4558,49 +1399,47 @@ static void dpp_build_legacy_cred_params(struct wpabuf *buf,
struct dpp_configuration *conf)
{
if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
- char pass[63 * 6 + 1];
-
- json_escape_string(pass, sizeof(pass), conf->passphrase,
- os_strlen(conf->passphrase));
- wpabuf_put_str(buf, "\"pass\":\"");
- wpabuf_put_str(buf, pass);
- wpabuf_put_str(buf, "\"");
- os_memset(pass, 0, sizeof(pass));
+ json_add_string_escape(buf, "pass", conf->passphrase,
+ os_strlen(conf->passphrase));
} else if (conf->psk_set) {
char psk[2 * sizeof(conf->psk) + 1];
wpa_snprintf_hex(psk, sizeof(psk),
conf->psk, sizeof(conf->psk));
- wpabuf_put_str(buf, "\"psk_hex\":\"");
- wpabuf_put_str(buf, psk);
- wpabuf_put_str(buf, "\"");
- os_memset(psk, 0, sizeof(psk));
+ json_add_string(buf, "psk_hex", psk);
+ forced_memzero(psk, sizeof(psk));
+ }
+}
+
+
+static const char * dpp_netrole_str(enum dpp_netrole netrole)
+{
+ switch (netrole) {
+ case DPP_NETROLE_STA:
+ return "sta";
+ case DPP_NETROLE_AP:
+ return "ap";
+ case DPP_NETROLE_CONFIGURATOR:
+ return "configurator";
+ default:
+ return "??";
}
}
static struct wpabuf *
-dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf = NULL;
- char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
+ char *signed_conn = NULL;
size_t tailroom;
const struct dpp_curve_params *curve;
- char jws_prot_hdr[100];
- size_t signed1_len, signed2_len, signed3_len;
struct wpabuf *dppcon = NULL;
- unsigned char *signature = NULL;
- const unsigned char *p;
- size_t signature_len;
- EVP_MD_CTX *md_ctx = NULL;
- ECDSA_SIG *sig = NULL;
- char *dot = ".";
- const EVP_MD *sign_md;
- const BIGNUM *r, *s;
size_t extra_len = 1000;
int incl_legacy;
enum dpp_akm akm;
+ const char *akm_str;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -4608,16 +1447,6 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
goto fail;
}
curve = auth->conf->curve;
- if (curve->hash_len == SHA256_MAC_LEN) {
- sign_md = EVP_sha256();
- } else if (curve->hash_len == SHA384_MAC_LEN) {
- sign_md = EVP_sha384();
- } else if (curve->hash_len == SHA512_MAC_LEN) {
- sign_md = EVP_sha512();
- } else {
- wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
- goto fail;
- }
akm = conf->akm;
if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
@@ -4647,142 +1476,136 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
auth->groups_override);
wpabuf_put_str(dppcon, "\"groups\":");
wpabuf_put_str(dppcon, auth->groups_override);
- wpabuf_put_u8(dppcon, ',');
+ json_value_sep(dppcon);
}
goto skip_groups;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
- conf->group_id ? conf->group_id : "*");
- wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+ json_start_object(dppcon, NULL);
+ json_start_array(dppcon, "groups");
+ json_start_object(dppcon, NULL);
+ json_add_string(dppcon, "groupId",
+ conf->group_id ? conf->group_id : "*");
+ json_value_sep(dppcon);
+ json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
+ json_end_object(dppcon);
+ json_end_array(dppcon);
+ json_value_sep(dppcon);
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
- if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
+ if (!auth->peer_protocol_key ||
+ dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
auth->curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
if (conf->netaccesskey_expiry) {
struct os_tm tm;
+ char expiry[30];
if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to generate expiry string");
goto fail;
}
- wpabuf_printf(dppcon,
- ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
- tm.year, tm.month, tm.day,
- tm.hour, tm.min, tm.sec);
- }
- wpabuf_put_u8(dppcon, '}');
+ os_snprintf(expiry, sizeof(expiry),
+ "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ tm.year, tm.month, tm.day,
+ tm.hour, tm.min, tm.sec);
+ json_value_sep(dppcon);
+ json_add_string(dppcon, "expiry", expiry);
+ }
+ json_end_object(dppcon);
wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
(const char *) wpabuf_head(dppcon));
- os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
- "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
- auth->conf->kid, curve->jws_alg);
- signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
- os_strlen(jws_prot_hdr),
- &signed1_len, 0);
- signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
- wpabuf_len(dppcon),
- &signed2_len, 0);
- if (!signed1 || !signed2)
- goto fail;
-
- md_ctx = EVP_MD_CTX_create();
- if (!md_ctx)
- goto fail;
-
- ERR_clear_error();
- if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
- auth->conf->csign) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
- EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
- EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- signature = os_malloc(signature_len);
- if (!signature)
- goto fail;
- if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
- signature, signature_len);
- /* Convert to raw coordinates r,s */
- p = signature;
- sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
- if (!sig)
- goto fail;
- ECDSA_SIG_get0(sig, &r, &s);
- if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(s, signature + curve->prime_len,
- curve->prime_len) < 0)
- goto fail;
- signature_len = 2 * curve->prime_len;
- wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
- signature, signature_len);
- signed3 = (char *) base64_url_encode(signature, signature_len,
- &signed3_len, 0);
- if (!signed3)
+ signed_conn = dpp_sign_connector(auth->conf, dppcon);
+ if (!signed_conn)
goto fail;
incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
tailroom = 1000;
tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
- tailroom += signed1_len + signed2_len + signed3_len;
+ tailroom += os_strlen(signed_conn);
if (incl_legacy)
tailroom += 1000;
+ if (akm == DPP_AKM_DOT1X) {
+ if (auth->certbag)
+ tailroom += 2 * wpabuf_len(auth->certbag);
+ if (auth->cacert)
+ tailroom += 2 * wpabuf_len(auth->cacert);
+ if (auth->trusted_eap_server_name)
+ tailroom += os_strlen(auth->trusted_eap_server_name);
+ tailroom += 1000;
+ }
buf = dpp_build_conf_start(auth, conf, tailroom);
if (!buf)
goto fail;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(akm))
+ akm_str = dpp_akm_selector_str(akm);
+ else
+ akm_str = dpp_akm_str(akm);
+ json_start_object(buf, "cred");
+ json_add_string(buf, "akm", akm_str);
+ json_value_sep(buf);
if (incl_legacy) {
dpp_build_legacy_cred_params(buf, conf);
- wpabuf_put_str(buf, ",");
+ json_value_sep(buf);
+ }
+ if (akm == DPP_AKM_DOT1X) {
+ json_start_object(buf, "entCreds");
+ if (!auth->certbag)
+ goto fail;
+ json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
+ wpabuf_len(auth->certbag));
+ if (auth->cacert) {
+ json_value_sep(buf);
+ json_add_base64(buf, "caCert",
+ wpabuf_head(auth->cacert),
+ wpabuf_len(auth->cacert));
+ }
+ if (auth->trusted_eap_server_name) {
+ json_value_sep(buf);
+ json_add_string(buf, "trustedEapServerName",
+ auth->trusted_eap_server_name);
+ }
+ json_value_sep(buf);
+ json_start_array(buf, "eapMethods");
+ wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
+ json_end_array(buf);
+ json_end_object(buf);
+ json_value_sep(buf);
}
wpabuf_put_str(buf, "\"signedConnector\":\"");
- wpabuf_put_str(buf, signed1);
- wpabuf_put_u8(buf, '.');
- wpabuf_put_str(buf, signed2);
- wpabuf_put_u8(buf, '.');
- wpabuf_put_str(buf, signed3);
- wpabuf_put_str(buf, "\",");
+ wpabuf_put_str(buf, signed_conn);
+ wpabuf_put_str(buf, "\"");
+ json_value_sep(buf);
if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
goto fail;
}
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 && auth->conf->pp_key) {
+ json_value_sep(buf);
+ if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
+ curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
+ goto fail;
+ }
+ }
+#endif /* CONFIG_DPP2 */
- wpabuf_put_str(buf, "}}");
+ json_end_object(buf);
+ json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
wpabuf_head(buf), wpabuf_len(buf));
out:
- EVP_MD_CTX_destroy(md_ctx);
- ECDSA_SIG_free(sig);
- os_free(signed1);
- os_free(signed2);
- os_free(signed3);
- os_free(signature);
+ os_free(signed_conn);
wpabuf_free(dppcon);
return buf;
fail:
@@ -4794,18 +1617,26 @@ fail:
static struct wpabuf *
-dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf;
+ const char *akm_str;
buf = dpp_build_conf_start(auth, conf, 1000);
if (!buf)
return NULL;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
+ akm_str = dpp_akm_selector_str(conf->akm);
+ else
+ akm_str = dpp_akm_str(conf->akm);
+ json_start_object(buf, "cred");
+ json_add_string(buf, "akm", akm_str);
+ json_value_sep(buf);
dpp_build_legacy_cred_params(buf, conf);
- wpabuf_put_str(buf, "}}");
+ json_end_object(buf);
+ json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
wpabuf_head(buf), wpabuf_len(buf));
@@ -4815,37 +1646,64 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
static struct wpabuf *
-dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
+ int idx, bool cert_req)
{
- struct dpp_configuration *conf;
+ struct dpp_configuration *conf = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (auth->config_obj_override) {
+ if (idx != 0)
+ return NULL;
wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
return wpabuf_alloc_copy(auth->config_obj_override,
os_strlen(auth->config_obj_override));
}
#endif /* CONFIG_TESTING_OPTIONS */
- conf = ap ? auth->conf_ap : auth->conf_sta;
+ if (idx == 0) {
+ if (netrole == DPP_NETROLE_STA)
+ conf = auth->conf_sta;
+ else if (netrole == DPP_NETROLE_AP)
+ conf = auth->conf_ap;
+ } else if (idx == 1) {
+ if (netrole == DPP_NETROLE_STA)
+ conf = auth->conf2_sta;
+ else if (netrole == DPP_NETROLE_AP)
+ conf = auth->conf2_ap;
+ }
if (!conf) {
- wpa_printf(MSG_DEBUG,
- "DPP: No configuration available for Enrollee(%s) - reject configuration request",
- ap ? "ap" : "sta");
+ if (idx == 0)
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+ dpp_netrole_str(netrole));
return NULL;
}
- if (dpp_akm_dpp(conf->akm))
- return dpp_build_conf_obj_dpp(auth, ap, conf);
- return dpp_build_conf_obj_legacy(auth, ap, conf);
+ if (conf->akm == DPP_AKM_DOT1X) {
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator data available");
+ return NULL;
+ }
+ if (!cert_req && !auth->certbag) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No certificate data available for dot1x configuration");
+ return NULL;
+ }
+ return dpp_build_conf_obj_dpp(auth, conf);
+ }
+ if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
+ return dpp_build_conf_obj_dpp(auth, conf);
+ return dpp_build_conf_obj_legacy(auth, conf);
}
-static struct wpabuf *
+struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
- u16 e_nonce_len, int ap)
+ u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
{
- struct wpabuf *conf;
+ struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -4853,18 +1711,49 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
size_t len[1];
enum dpp_status_error status;
- conf = dpp_build_conf_obj(auth, ap);
- if (conf) {
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- wpabuf_head(conf), wpabuf_len(conf));
+ if (auth->force_conf_resp_status != DPP_STATUS_OK) {
+ status = auth->force_conf_resp_status;
+ goto forced_status;
}
- status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+
+ if (netrole == DPP_NETROLE_CONFIGURATOR) {
+#ifdef CONFIG_DPP2
+ env_data = dpp_build_enveloped_data(auth);
+#endif /* CONFIG_DPP2 */
+ } else {
+ conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
+ if (conf) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: configurationObject JSON",
+ wpabuf_head(conf), wpabuf_len(conf));
+ conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
+ }
+ }
+
+ if (conf || env_data)
+ status = DPP_STATUS_OK;
+ else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
+ auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
+ status = DPP_STATUS_CSR_NEEDED;
+ else
+ status = DPP_STATUS_CONFIGURE_FAILURE;
+forced_status:
auth->conf_resp_status = status;
- /* { E-nonce, configurationObject}ke */
+ /* { E-nonce, configurationObject[, sendConnStatus]}ke */
clear_len = 4 + e_nonce_len;
if (conf)
clear_len += 4 + wpabuf_len(conf);
+ if (conf2)
+ clear_len += 4 + wpabuf_len(conf2);
+ if (env_data)
+ clear_len += 4 + wpabuf_len(env_data);
+ if (auth->peer_version >= 2 && auth->send_conn_status &&
+ netrole == DPP_NETROLE_STA)
+ clear_len += 4;
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs)
+ clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -4912,6 +1801,35 @@ skip_e_nonce:
wpabuf_put_le16(clear, wpabuf_len(conf));
wpabuf_put_buf(clear, conf);
}
+ if (auth->peer_version >= 2 && conf2) {
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+ wpabuf_put_le16(clear, wpabuf_len(conf2));
+ wpabuf_put_buf(clear, conf2);
+ } else if (conf2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Second Config Object available, but peer does not support more than one");
+ }
+ if (env_data) {
+ wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
+ wpabuf_put_le16(clear, wpabuf_len(env_data));
+ wpabuf_put_buf(clear, env_data);
+ }
+
+ if (auth->peer_version >= 2 && auth->send_conn_status &&
+ netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
+ wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
+ wpabuf_put_le16(clear, 0);
+ }
+
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs) {
+ auth->waiting_csr = true;
+ wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
+ wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
+ wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
+ wpabuf_put_str(clear, auth->conf_sta->csrattrs);
+ }
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
@@ -4959,8 +1877,10 @@ skip_wrapped_data:
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Response attributes", msg);
out:
- wpabuf_free(conf);
- wpabuf_free(clear);
+ wpabuf_clear_free(conf);
+ wpabuf_clear_free(conf2);
+ wpabuf_clear_free(env_data);
+ wpabuf_clear_free(clear);
return msg;
fail:
@@ -4980,7 +1900,8 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t unwrapped_len = 0;
struct wpabuf *resp = NULL;
struct json_token *root = NULL, *token;
- int ap;
+ enum dpp_netrole netrole;
+ struct wpabuf *cert_req = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -5078,106 +1999,121 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
}
wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
if (os_strcmp(token->string, "sta") == 0) {
- ap = 0;
+ netrole = DPP_NETROLE_STA;
} else if (os_strcmp(token->string, "ap") == 0) {
- ap = 1;
+ netrole = DPP_NETROLE_AP;
+ } else if (os_strcmp(token->string, "configurator") == 0) {
+ netrole = DPP_NETROLE_CONFIGURATOR;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
token->string);
dpp_auth_fail(auth, "Unsupported netRole");
goto fail;
}
+ auth->e_netrole = netrole;
+
+ token = json_get_member(root, "mudurl");
+ if (token && token->type == JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
+ token->string);
+ }
+
+ token = json_get_member(root, "bandSupport");
+ if (token && token->type == JSON_ARRAY) {
+ int *opclass = NULL;
+ char txt[200], *pos, *end;
+ int i, res;
+
+ wpa_printf(MSG_DEBUG, "DPP: bandSupport");
+ token = token->child;
+ while (token) {
+ if (token->type != JSON_NUMBER) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid bandSupport array member type");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Supported global operating class: %d",
+ token->number);
+ int_array_add_unique(&opclass, token->number);
+ }
+ token = token->sibling;
+ }
- resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
-
-fail:
- json_free(root);
- os_free(unwrapped);
- return resp;
-}
-
-
-static struct wpabuf *
-dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
- const u8 *prot_hdr, u16 prot_hdr_len,
- const EVP_MD **ret_md)
-{
- struct json_token *root, *token;
- struct wpabuf *kid = NULL;
-
- root = json_parse((const char *) prot_hdr, prot_hdr_len);
- if (!root) {
- wpa_printf(MSG_DEBUG,
- "DPP: JSON parsing failed for JWS Protected Header");
- goto fail;
+ txt[0] = '\0';
+ pos = txt;
+ end = txt + sizeof(txt);
+ for (i = 0; opclass && opclass[i]; i++) {
+ res = os_snprintf(pos, end - pos, "%s%d",
+ pos == txt ? "" : ",", opclass[i]);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ }
+ os_free(opclass);
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
+ txt);
}
- if (root->type != JSON_OBJECT) {
- wpa_printf(MSG_DEBUG,
- "DPP: JWS Protected Header root is not an object");
- goto fail;
- }
+#ifdef CONFIG_DPP2
+ cert_req = json_get_member_base64(root, "pkcs10");
+ if (cert_req) {
+ char *txt;
+ int id;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
+ if (dpp_validate_csr(auth, cert_req) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
+ auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
+ goto cont;
+ }
- token = json_get_member(root, "typ");
- if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
- token->string);
- if (os_strcmp(token->string, "dppCon") != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported JWS Protected Header typ=%s",
- token->string);
- goto fail;
- }
+ if (auth->peer_bi) {
+ id = auth->peer_bi->id;
+ } else if (auth->tmp_peer_bi) {
+ id = auth->tmp_peer_bi->id;
+ } else {
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ goto fail;
+ bi->id = dpp_next_id(auth->global);
+ dl_list_add(&auth->global->bootstrap, &bi->list);
+ auth->tmp_peer_bi = bi;
+ id = bi->id;
+ }
- token = json_get_member(root, "alg");
- if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
- token->string);
- if (os_strcmp(token->string, curve->jws_alg) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
- token->string, curve->jws_alg);
- goto fail;
- }
- if (os_strcmp(token->string, "ES256") == 0 ||
- os_strcmp(token->string, "BS256") == 0)
- *ret_md = EVP_sha256();
- else if (os_strcmp(token->string, "ES384") == 0 ||
- os_strcmp(token->string, "BS384") == 0)
- *ret_md = EVP_sha384();
- else if (os_strcmp(token->string, "ES512") == 0 ||
- os_strcmp(token->string, "BS512") == 0)
- *ret_md = EVP_sha512();
- else
- *ret_md = NULL;
- if (!*ret_md) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported JWS Protected Header alg=%s",
- token->string);
- goto fail;
- }
+ wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
+ txt = base64_encode_no_lf(wpabuf_head(cert_req),
+ wpabuf_len(cert_req), NULL);
+ if (!txt)
+ goto fail;
- kid = json_get_member_base64url(root, "kid");
- if (!kid) {
- wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
+ id, txt);
+ os_free(txt);
+ auth->waiting_csr = false;
+ auth->waiting_cert = true;
goto fail;
}
- wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
- kid);
+cont:
+#endif /* CONFIG_DPP2 */
+
+ resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
+ cert_req);
fail:
+ wpabuf_free(cert_req);
json_free(root);
- return kid;
+ os_free(unwrapped);
+ return resp;
}
-static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
struct json_token *cred)
{
struct json_token *pass, *psk_hex;
@@ -5194,28 +2130,28 @@ static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
pass->string, len);
if (len < 8 || len > 63)
return -1;
- os_strlcpy(auth->passphrase, pass->string,
- sizeof(auth->passphrase));
+ os_strlcpy(conf->passphrase, pass->string,
+ sizeof(conf->passphrase));
} else if (psk_hex && psk_hex->type == JSON_STRING) {
- if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected psk_hex with akm=sae");
return -1;
}
if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
- hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
+ hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
- auth->psk, PMK_LEN);
- auth->psk_set = 1;
+ conf->psk, PMK_LEN);
+ conf->psk_set = 1;
} else {
wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
return -1;
}
- if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
return -1;
}
@@ -5224,8 +2160,8 @@ static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
}
-static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
- const struct dpp_curve_params **key_curve)
+EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
+ const struct dpp_curve_params **key_curve)
{
struct json_token *token;
const struct dpp_curve_params *curve;
@@ -5383,6 +2319,7 @@ int dpp_key_expired(const char *timestamp, os_time_t *expiry)
static int dpp_parse_connector(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
const unsigned char *payload,
u16 payload_len)
{
@@ -5478,59 +2415,49 @@ fail:
}
-static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
+static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
{
- struct wpabuf *uncomp;
- int res;
- u8 hash[SHA256_MAC_LEN];
- const u8 *addr[1];
- size_t len[1];
+ unsigned char *der = NULL;
+ int der_len;
- if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
- return -1;
- uncomp = dpp_get_pubkey_point(pub, 1);
- if (!uncomp)
- return -1;
- addr[0] = wpabuf_head(uncomp);
- len[0] = wpabuf_len(uncomp);
- wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
- addr[0], len[0]);
- res = sha256_vector(1, addr, len, hash);
- wpabuf_free(uncomp);
- if (res < 0)
- return -1;
- if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Received hash value does not match calculated public key hash value");
- wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
- hash, SHA256_MAC_LEN);
- return -1;
- }
- return 0;
+ der_len = i2d_PUBKEY(csign, &der);
+ if (der_len <= 0)
+ return;
+ wpabuf_free(conf->c_sign_key);
+ conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
}
-static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+static void dpp_copy_ppkey(struct dpp_config_obj *conf, EVP_PKEY *ppkey)
{
unsigned char *der = NULL;
int der_len;
- der_len = i2d_PUBKEY(csign, &der);
+ der_len = i2d_PUBKEY(ppkey, &der);
if (der_len <= 0)
return;
- wpabuf_free(auth->c_sign_key);
- auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ wpabuf_free(conf->pp_key);
+ conf->pp_key = wpabuf_alloc_copy(der, der_len);
OPENSSL_free(der);
}
-static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
unsigned char *der = NULL;
int der_len;
EC_KEY *eckey;
+ EVP_PKEY *own_key;
- eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
+ own_key = auth->own_protocol_key;
+#ifdef CONFIG_DPP2
+ if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
+ auth->reconfig_old_protocol_key)
+ own_key = auth->reconfig_old_protocol_key;
+#endif /* CONFIG_DPP2 */
+ eckey = EVP_PKEY_get1_EC_KEY(own_key);
if (!eckey)
return;
@@ -5546,193 +2473,23 @@ static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
}
-struct dpp_signed_connector_info {
- unsigned char *payload;
- size_t payload_len;
-};
-
-static enum dpp_status_error
-dpp_process_signed_connector(struct dpp_signed_connector_info *info,
- EVP_PKEY *csign_pub, const char *connector)
-{
- enum dpp_status_error ret = 255;
- const char *pos, *end, *signed_start, *signed_end;
- struct wpabuf *kid = NULL;
- unsigned char *prot_hdr = NULL, *signature = NULL;
- size_t prot_hdr_len = 0, signature_len = 0;
- const EVP_MD *sign_md = NULL;
- unsigned char *der = NULL;
- int der_len;
- int res;
- EVP_MD_CTX *md_ctx = NULL;
- ECDSA_SIG *sig = NULL;
- BIGNUM *r = NULL, *s = NULL;
- const struct dpp_curve_params *curve;
- EC_KEY *eckey;
- const EC_GROUP *group;
- int nid;
-
- eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
- if (!eckey)
- goto fail;
- group = EC_KEY_get0_group(eckey);
- if (!group)
- goto fail;
- nid = EC_GROUP_get_curve_name(group);
- curve = dpp_get_curve_nid(nid);
- if (!curve)
- goto fail;
- wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
- os_memset(info, 0, sizeof(*info));
-
- signed_start = pos = connector;
- end = os_strchr(pos, '.');
- if (!end) {
- wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- prot_hdr = base64_url_decode((const unsigned char *) pos,
- end - pos, &prot_hdr_len);
- if (!prot_hdr) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to base64url decode signedConnector JWS Protected Header");
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- wpa_hexdump_ascii(MSG_DEBUG,
- "DPP: signedConnector - JWS Protected Header",
- prot_hdr, prot_hdr_len);
- kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
- if (!kid) {
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- if (wpabuf_len(kid) != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
- (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
-
- pos = end + 1;
- end = os_strchr(pos, '.');
- if (!end) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing dot(2) in signedConnector");
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- signed_end = end - 1;
- info->payload = base64_url_decode((const unsigned char *) pos,
- end - pos, &info->payload_len);
- if (!info->payload) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to base64url decode signedConnector JWS Payload");
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- wpa_hexdump_ascii(MSG_DEBUG,
- "DPP: signedConnector - JWS Payload",
- info->payload, info->payload_len);
- pos = end + 1;
- signature = base64_url_decode((const unsigned char *) pos,
- os_strlen(pos), &signature_len);
- if (!signature) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to base64url decode signedConnector signature");
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
- signature, signature_len);
-
- if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
- ret = DPP_STATUS_NO_MATCH;
- goto fail;
- }
-
- if (signature_len & 0x01) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unexpected signedConnector signature length (%d)",
- (int) signature_len);
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
-
- /* JWS Signature encodes the signature (r,s) as two octet strings. Need
- * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
- r = BN_bin2bn(signature, signature_len / 2, NULL);
- s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
- sig = ECDSA_SIG_new();
- if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
- goto fail;
- r = NULL;
- s = NULL;
-
- der_len = i2d_ECDSA_SIG(sig, &der);
- if (der_len <= 0) {
- wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
- md_ctx = EVP_MD_CTX_create();
- if (!md_ctx)
- goto fail;
-
- ERR_clear_error();
- if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
- signed_end - signed_start + 1) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
- if (res != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
- res, ERR_error_string(ERR_get_error(), NULL));
- ret = DPP_STATUS_INVALID_CONNECTOR;
- goto fail;
- }
-
- ret = DPP_STATUS_OK;
-fail:
- EC_KEY_free(eckey);
- EVP_MD_CTX_destroy(md_ctx);
- os_free(prot_hdr);
- wpabuf_free(kid);
- os_free(signature);
- ECDSA_SIG_free(sig);
- BN_free(r);
- BN_free(s);
- OPENSSL_free(der);
- return ret;
-}
-
-
static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
struct json_token *cred)
{
struct dpp_signed_connector_info info;
- struct json_token *token, *csign;
+ struct json_token *token, *csign, *ppkey;
int ret = -1;
- EVP_PKEY *csign_pub = NULL;
- const struct dpp_curve_params *key_curve = NULL;
+ EVP_PKEY *csign_pub = NULL, *pp_pub = NULL;
+ const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
const char *signed_connector;
os_memset(&info, 0, sizeof(info));
- if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Legacy credential included in Connector credential");
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
return -1;
}
@@ -5751,6 +2508,21 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
}
dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
+ ppkey = json_get_member(cred, "ppKey");
+ if (ppkey && ppkey->type == JSON_OBJECT) {
+ pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
+ if (!pp_pub) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Received ppKey", pp_pub);
+ if (key_curve != pp_curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: C-sign-key and ppKey do not use the same curve");
+ goto fail;
+ }
+ }
+
token = json_get_member(cred, "signedConnector");
if (!token || token->type != JSON_STRING) {
wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
@@ -5771,25 +2543,82 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
signed_connector) != DPP_STATUS_OK)
goto fail;
- if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+ if (dpp_parse_connector(auth, conf,
+ info.payload, info.payload_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
goto fail;
}
- os_free(auth->connector);
- auth->connector = os_strdup(signed_connector);
+ os_free(conf->connector);
+ conf->connector = os_strdup(signed_connector);
- dpp_copy_csign(auth, csign_pub);
- dpp_copy_netaccesskey(auth);
+ dpp_copy_csign(conf, csign_pub);
+ if (pp_pub)
+ dpp_copy_ppkey(conf, pp_pub);
+ if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
+ dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
EVP_PKEY_free(csign_pub);
+ EVP_PKEY_free(pp_pub);
os_free(info.payload);
return ret;
}
+#ifdef CONFIG_DPP2
+static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
+ struct json_token *cred)
+{
+ struct json_token *ent, *name;
+
+ ent = json_get_member(cred, "entCreds");
+ if (!ent || ent->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No entCreds in JSON");
+ return -1;
+ }
+
+ conf->certbag = json_get_member_base64(ent, "certBag");
+ if (!conf->certbag) {
+ dpp_auth_fail(auth, "No certBag in JSON");
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
+ conf->certs = dpp_pkcs7_certs(conf->certbag);
+ if (!conf->certs) {
+ dpp_auth_fail(auth, "No certificates in certBag");
+ return -1;
+ }
+
+ conf->cacert = json_get_member_base64(ent, "caCert");
+ if (conf->cacert)
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
+ conf->cacert);
+
+ name = json_get_member(ent, "trustedEapServerName");
+ if (name &&
+ (name->type != JSON_STRING ||
+ has_ctrl_char((const u8 *) name->string,
+ os_strlen(name->string)))) {
+ dpp_auth_fail(auth,
+ "Invalid trustedEapServerName type in JSON");
+ return -1;
+ }
+ if (name && name->string) {
+ wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
+ name->string);
+ conf->server_name = os_strdup(name->string);
+ if (!conf->server_name)
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
const char * dpp_akm_str(enum dpp_akm akm)
{
switch (akm) {
@@ -5805,6 +2634,31 @@ const char * dpp_akm_str(enum dpp_akm akm)
return "dpp+sae";
case DPP_AKM_PSK_SAE_DPP:
return "dpp+psk+sae";
+ case DPP_AKM_DOT1X:
+ return "dot1x";
+ default:
+ return "??";
+ }
+}
+
+
+const char * dpp_akm_selector_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "506F9A02";
+ case DPP_AKM_PSK:
+ return "000FAC02+000FAC06";
+ case DPP_AKM_SAE:
+ return "000FAC08";
+ case DPP_AKM_PSK_SAE:
+ return "000FAC02+000FAC06+000FAC08";
+ case DPP_AKM_SAE_DPP:
+ return "506F9A02+000FAC08";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "506F9A02+000FAC08+000FAC02+000FAC06";
+ case DPP_AKM_DOT1X:
+ return "000FAC01+000FAC05";
default:
return "??";
}
@@ -5813,6 +2667,9 @@ const char * dpp_akm_str(enum dpp_akm akm)
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
+ const char *pos;
+ int dpp = 0, psk = 0, sae = 0, dot1x = 0;
+
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
if (os_strcmp(akm, "sae") == 0)
@@ -5825,6 +2682,46 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+ if (os_strcmp(akm, "dot1x") == 0)
+ return DPP_AKM_DOT1X;
+
+ pos = akm;
+ while (*pos) {
+ if (os_strlen(pos) < 8)
+ break;
+ if (os_strncasecmp(pos, "506F9A02", 8) == 0)
+ dpp = 1;
+ else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
+ sae = 1;
+ else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
+ dot1x = 1;
+ else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
+ dot1x = 1;
+ pos += 8;
+ if (*pos != '+')
+ break;
+ pos++;
+ }
+
+ if (dpp && psk && sae)
+ return DPP_AKM_PSK_SAE_DPP;
+ if (dpp && sae)
+ return DPP_AKM_SAE_DPP;
+ if (dpp)
+ return DPP_AKM_DPP;
+ if (psk && sae)
+ return DPP_AKM_PSK_SAE;
+ if (sae)
+ return DPP_AKM_SAE;
+ if (psk)
+ return DPP_AKM_PSK;
+ if (dot1x)
+ return DPP_AKM_DOT1X;
+
return DPP_AKM_UNKNOWN;
}
@@ -5834,6 +2731,9 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
{
int ret = -1;
struct json_token *root, *token, *discovery, *cred;
+ struct dpp_config_obj *conf;
+ struct wpabuf *ssid64 = NULL;
+ int legacy;
root = json_parse((const char *) conf_obj, conf_obj_len);
if (!root)
@@ -5861,19 +2761,52 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
goto fail;
}
- token = json_get_member(discovery, "ssid");
- if (!token || token->type != JSON_STRING) {
- dpp_auth_fail(auth, "No discovery::ssid string value found");
- goto fail;
+ ssid64 = json_get_member_base64url(discovery, "ssid64");
+ if (ssid64) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
+ wpabuf_head(ssid64), wpabuf_len(ssid64));
+ if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
+ dpp_auth_fail(auth, "Too long discovery::ssid64 value");
+ goto fail;
+ }
+ } else {
+ token = json_get_member(discovery, "ssid");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth,
+ "No discovery::ssid string value found");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
+ token->string, os_strlen(token->string));
+ if (os_strlen(token->string) > SSID_MAX_LEN) {
+ dpp_auth_fail(auth,
+ "Too long discovery::ssid string value");
+ goto fail;
+ }
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
- token->string, os_strlen(token->string));
- if (os_strlen(token->string) > SSID_MAX_LEN) {
- dpp_auth_fail(auth, "Too long discovery::ssid string value");
+
+ if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No room for this many Config Objects - ignore this one");
+ ret = 0;
goto fail;
}
- auth->ssid_len = os_strlen(token->string);
- os_memcpy(auth->ssid, token->string, auth->ssid_len);
+ conf = &auth->conf_obj[auth->num_conf_obj++];
+
+ if (ssid64) {
+ conf->ssid_len = wpabuf_len(ssid64);
+ os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
+ } else {
+ conf->ssid_len = os_strlen(token->string);
+ os_memcpy(conf->ssid, token->string, conf->ssid_len);
+ }
+
+ token = json_get_member(discovery, "ssid_charset");
+ if (token && token->type == JSON_NUMBER) {
+ conf->ssid_charset = token->number;
+ wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
+ conf->ssid_charset);
+ }
cred = json_get_member(root, "cred");
if (!cred || cred->type != JSON_OBJECT) {
@@ -5886,14 +2819,31 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
dpp_auth_fail(auth, "No cred::akm string value found");
goto fail;
}
- auth->akm = dpp_akm_from_str(token->string);
+ conf->akm = dpp_akm_from_str(token->string);
- if (dpp_akm_legacy(auth->akm)) {
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ legacy = dpp_akm_legacy(conf->akm);
+ if (legacy && auth->peer_version >= 2) {
+ struct json_token *csign, *s_conn;
+
+ csign = json_get_member(cred, "csign");
+ s_conn = json_get_member(cred, "signedConnector");
+ if (csign && csign->type == JSON_OBJECT &&
+ s_conn && s_conn->type == JSON_STRING)
+ legacy = 0;
+ }
+ if (legacy) {
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
goto fail;
- } else if (dpp_akm_dpp(auth->akm)) {
- if (dpp_parse_cred_dpp(auth, cred) < 0)
+ } else if (dpp_akm_dpp(conf->akm) ||
+ (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
+ if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
+#ifdef CONFIG_DPP2
+ } else if (conf->akm == DPP_AKM_DOT1X) {
+ if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
+ dpp_parse_cred_dpp(auth, conf, cred) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
token->string);
@@ -5904,16 +2854,33 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
ret = 0;
fail:
+ wpabuf_free(ssid64);
json_free(root);
return ret;
}
+#ifdef CONFIG_DPP2
+static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
+{
+ const u8 *b64;
+ u16 b64_len;
+
+ b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
+ if (!b64)
+ return NULL;
+ return base64_decode((const char *) b64, b64_len, len);
+}
+#endif /* CONFIG_DPP2 */
+
+
int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp)
{
const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
+ const u8 *env_data;
+ u16 env_data_len;
const u8 *addr[1];
size_t len[1];
u8 *unwrapped = NULL;
@@ -5984,22 +2951,67 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
}
auth->conf_resp_status = status[0];
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+#ifdef CONFIG_DPP2
+ if (status[0] == DPP_STATUS_CSR_NEEDED) {
+ u8 *csrattrs;
+ size_t csrattrs_len;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
+
+ csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
+ &csrattrs_len);
+ if (!csrattrs) {
+ dpp_auth_fail(auth,
+ "Missing or invalid CSR Attributes Request attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
+ os_free(auth->csrattrs);
+ auth->csrattrs = csrattrs;
+ auth->csrattrs_len = csrattrs_len;
+ ret = -2;
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 */
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
}
- conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
- if (!conf_obj) {
+ env_data = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENVELOPED_DATA, &env_data_len);
+#ifdef CONFIG_DPP2
+ if (env_data &&
+ dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
+
+ conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ if (!conf_obj && !env_data) {
dpp_auth_fail(auth,
"Missing required Configuration Object attribute");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- conf_obj, conf_obj_len);
- if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
- goto fail;
+ while (conf_obj) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ conf_obj, conf_obj_len);
+ if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+ goto fail;
+ conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ }
+
+#ifdef CONFIG_DPP2
+ status = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_SEND_CONN_STATUS, &status_len);
+ if (status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested connection status result");
+ auth->conn_status_requested = 1;
+ }
+#endif /* CONFIG_DPP2 */
ret = 0;
@@ -6010,6 +3022,7 @@ fail:
#ifdef CONFIG_DPP2
+
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *hdr,
const u8 *attr_start, size_t attr_len)
@@ -6090,7 +3103,6 @@ fail:
bin_clear_free(unwrapped, unwrapped_len);
return ret;
}
-#endif /* CONFIG_DPP2 */
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
@@ -6108,7 +3120,7 @@ struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
clear = wpabuf_alloc(clear_len);
msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
if (!clear || !msg)
- return NULL;
+ goto fail;
/* DPP Status */
dpp_build_attr_status(clear, status);
@@ -6149,12 +3161,244 @@ fail:
}
+static int valid_channel_list(const char *val)
+{
+ while (*val) {
+ if (!((*val >= '0' && *val <= '9') ||
+ *val == '/' || *val == ','))
+ return 0;
+ val++;
+ }
+
+ return 1;
+}
+
+
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list)
+{
+ const u8 *wrapped_data, *status, *e_nonce;
+ u16 wrapped_data_len, status_len, e_nonce_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ enum dpp_status_error ret = 256;
+ struct json_token *root = NULL, *token;
+ struct wpabuf *ssid64;
+
+ *ssid_len = 0;
+ *channel_list = NULL;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+ auth->e_nonce, e_nonce_len);
+ goto fail;
+ }
+
+ status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
+ &status_len);
+ if (!status) {
+ dpp_auth_fail(auth,
+ "Missing required DPP Connection Status attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ status, status_len);
+
+ root = json_parse((const char *) status, status_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Could not parse connStatus");
+ goto fail;
+ }
+
+ ssid64 = json_get_member_base64url(root, "ssid64");
+ if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
+ *ssid_len = wpabuf_len(ssid64);
+ os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
+ }
+ wpabuf_free(ssid64);
+
+ token = json_get_member(root, "channelList");
+ if (token && token->type == JSON_STRING &&
+ valid_channel_list(token->string))
+ *channel_list = os_strdup(token->string);
+
+ token = json_get_member(root, "result");
+ if (!token || token->type != JSON_NUMBER) {
+ dpp_auth_fail(auth, "No connStatus - result");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
+ ret = token->number;
+
+fail:
+ json_free(root);
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+
+
+struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *json;
+
+ json = wpabuf_alloc(1000);
+ if (!json)
+ return NULL;
+ json_start_object(json, NULL);
+ json_add_int(json, "result", result);
+ if (ssid) {
+ json_value_sep(json);
+ if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
+ wpabuf_free(json);
+ return NULL;
+ }
+ }
+ if (channel_list) {
+ json_value_sep(json);
+ json_add_string(json, "channelList", channel_list);
+ }
+ json_end_object(json);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ wpabuf_head(json), wpabuf_len(json));
+
+ return json;
+}
+
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *msg = NULL, *clear = NULL, *json;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
+ if (!json)
+ return NULL;
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* DPP Connection Status */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(json));
+ wpabuf_put_buf(clear, json);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
+ msg);
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
return;
EVP_PKEY_free(conf->csign);
os_free(conf->kid);
+ os_free(conf->connector);
+ EVP_PKEY_free(conf->connector_key);
+ EVP_PKEY_free(conf->pp_key);
os_free(conf);
}
@@ -6183,66 +3427,73 @@ int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
}
-struct dpp_configurator *
-dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len)
+static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
{
- struct dpp_configurator *conf;
struct wpabuf *csign_pub = NULL;
- u8 kid_hash[SHA256_MAC_LEN];
const u8 *addr[1];
size_t len[1];
+ int res;
+
+ csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+ if (!csign_pub) {
+ wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+ return -1;
+ }
+
+ /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
+ addr[0] = wpabuf_head(csign_pub);
+ len[0] = wpabuf_len(csign_pub);
+ res = sha256_vector(1, addr, len, conf->kid_hash);
+ wpabuf_free(csign_pub);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to derive kid for C-sign-key");
+ return -1;
+ }
+
+ conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
+ NULL);
+ return conf->kid ? 0 : -1;
+}
+
+
+static struct dpp_configurator *
+dpp_keygen_configurator(const char *curve, const u8 *privkey,
+ size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
+{
+ struct dpp_configurator *conf;
conf = os_zalloc(sizeof(*conf));
if (!conf)
return NULL;
- if (!curve) {
- conf->curve = &dpp_curves[0];
- } else {
- conf->curve = dpp_get_curve_name(curve);
- if (!conf->curve) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
- curve);
- os_free(conf);
- return NULL;
- }
+ conf->curve = dpp_get_curve_name(curve);
+ if (!conf->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
+ os_free(conf);
+ return NULL;
}
+
if (privkey)
conf->csign = dpp_set_keypair(&conf->curve, privkey,
privkey_len);
else
conf->csign = dpp_gen_keypair(conf->curve);
- if (!conf->csign)
+ if (pp_key)
+ conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
+ pp_key_len);
+ else
+ conf->pp_key = dpp_gen_keypair(conf->curve);
+ if (!conf->csign || !conf->pp_key)
goto fail;
conf->own = 1;
- csign_pub = dpp_get_pubkey_point(conf->csign, 1);
- if (!csign_pub) {
- wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
- goto fail;
- }
-
- /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
- addr[0] = wpabuf_head(csign_pub);
- len[0] = wpabuf_len(csign_pub);
- if (sha256_vector(1, addr, len, kid_hash) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to derive kid for C-sign-key");
- goto fail;
- }
-
- conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
- NULL, 0);
- if (!conf->kid)
+ if (dpp_configurator_gen_kid(conf) < 0)
goto fail;
-out:
- wpabuf_free(csign_pub);
return conf;
fail:
dpp_configurator_free(conf);
- conf = NULL;
- goto out;
+ return NULL;
}
@@ -6257,16 +3508,12 @@ int dpp_configurator_own_config(struct dpp_authentication *auth,
return -1;
}
- if (!curve) {
- auth->curve = &dpp_curves[0];
- } else {
- auth->curve = dpp_get_curve_name(curve);
- if (!auth->curve) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
- curve);
- return -1;
- }
+ auth->curve = dpp_get_curve_name(curve);
+ if (!auth->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
+ return -1;
}
+
wpa_printf(MSG_DEBUG,
"DPP: Building own configuration/connector with curve %s",
auth->curve->name);
@@ -6274,13 +3521,16 @@ int dpp_configurator_own_config(struct dpp_authentication *auth,
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
if (!auth->own_protocol_key)
return -1;
- dpp_copy_netaccesskey(auth);
+ dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
auth->peer_protocol_key = auth->own_protocol_key;
- dpp_copy_csign(auth, auth->conf->csign);
+ dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap);
- if (!conf_obj)
+ conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
+ if (!conf_obj) {
+ wpabuf_free(auth->conf_obj[0].c_sign_key);
+ auth->conf_obj[0].c_sign_key = NULL;
goto fail;
+ }
ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
wpabuf_len(conf_obj));
fail:
@@ -6299,7 +3549,8 @@ static int dpp_compatible_netrole(const char *role1, const char *role2)
static int dpp_connector_compatible_group(struct json_token *root,
const char *group_id,
- const char *net_role)
+ const char *net_role,
+ bool reconfig)
{
struct json_token *groups, *token;
@@ -6323,7 +3574,9 @@ static int dpp_connector_compatible_group(struct json_token *root,
os_strcmp(id->string, group_id) != 0)
continue;
- if (dpp_compatible_netrole(role->string, net_role))
+ if (reconfig && os_strcmp(net_role, "configurator") == 0)
+ return 1;
+ if (!reconfig && dpp_compatible_netrole(role->string, net_role))
return 1;
}
@@ -6331,8 +3584,8 @@ static int dpp_connector_compatible_group(struct json_token *root,
}
-static int dpp_connector_match_groups(struct json_token *own_root,
- struct json_token *peer_root)
+int dpp_connector_match_groups(struct json_token *own_root,
+ struct json_token *peer_root, bool reconfig)
{
struct json_token *groups, *token;
@@ -6362,7 +3615,7 @@ static int dpp_connector_match_groups(struct json_token *own_root,
"DPP: peer connector group: groupId='%s' netRole='%s'",
id->string, role->string);
if (dpp_connector_compatible_group(own_root, id->string,
- role->string)) {
+ role->string, reconfig)) {
wpa_printf(MSG_DEBUG,
"DPP: Compatible group/netRole in own connector");
return 1;
@@ -6373,71 +3626,37 @@ static int dpp_connector_match_groups(struct json_token *own_root,
}
-static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
- unsigned int hash_len)
+struct json_token * dpp_parse_own_connector(const char *own_connector)
{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- const char *info = "DPP PMK";
- int res;
-
- /* PMK = HKDF(<>, "DPP PMK", N.x) */
-
- /* HKDF-Extract(<>, N.x) */
- os_memset(salt, 0, hash_len);
- if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
- pmk, hash_len);
- return 0;
-}
+ unsigned char *own_conn;
+ size_t own_conn_len;
+ const char *pos, *end;
+ struct json_token *own_root;
+ pos = os_strchr(own_connector, '.');
+ if (!pos) {
+ wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
+ return NULL;
+ }
+ pos++;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
+ return NULL;
+ }
+ own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
+ if (!own_conn) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode own signedConnector JWS Payload");
+ return NULL;
+ }
-static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
- EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
-{
- struct wpabuf *nkx, *pkx;
- int ret = -1, res;
- const u8 *addr[2];
- size_t len[2];
- u8 hash[SHA256_MAC_LEN];
+ own_root = json_parse((const char *) own_conn, own_conn_len);
+ os_free(own_conn);
+ if (!own_root)
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
- /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
- nkx = dpp_get_pubkey_point(own_key, 0);
- pkx = dpp_get_pubkey_point(peer_key, 0);
- if (!nkx || !pkx)
- goto fail;
- addr[0] = wpabuf_head(nkx);
- len[0] = wpabuf_len(nkx) / 2;
- addr[1] = wpabuf_head(pkx);
- len[1] = wpabuf_len(pkx) / 2;
- if (len[0] != len[1])
- goto fail;
- if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
- addr[0] = wpabuf_head(pkx);
- addr[1] = wpabuf_head(nkx);
- }
- wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
- res = sha256_vector(2, addr, len, hash);
- if (res < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
- os_memcpy(pmkid, hash, PMKID_LEN);
- wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
- ret = 0;
-fail:
- wpabuf_free(nkx);
- wpabuf_free(pkx);
- return ret;
+ return own_root;
}
@@ -6455,12 +3674,6 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
struct wpabuf *own_key_pub = NULL;
const struct dpp_curve_params *curve, *own_curve;
struct dpp_signed_connector_info info;
- const unsigned char *p;
- EVP_PKEY *csign = NULL;
- char *signed_connector = NULL;
- const char *pos, *end;
- unsigned char *own_conn = NULL;
- size_t own_conn_len;
size_t Nx_len;
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
@@ -6469,14 +3682,6 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
if (expiry)
*expiry = 0;
- p = csign_key;
- csign = d2i_PUBKEY(NULL, &p, csign_key_len);
- if (!csign) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to parse local C-sign-key information");
- goto fail;
- }
-
own_key = dpp_set_keypair(&own_curve, net_access_key,
net_access_key_len);
if (!own_key) {
@@ -6484,40 +3689,12 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
goto fail;
}
- pos = os_strchr(own_connector, '.');
- if (!pos) {
- wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
- goto fail;
- }
- pos++;
- end = os_strchr(pos, '.');
- if (!end) {
- wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
- goto fail;
- }
- own_conn = base64_url_decode((const unsigned char *) pos,
- end - pos, &own_conn_len);
- if (!own_conn) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to base64url decode own signedConnector JWS Payload");
- goto fail;
- }
-
- own_root = json_parse((const char *) own_conn, own_conn_len);
- if (!own_root) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
+ own_root = dpp_parse_own_connector(own_connector);
+ if (!own_root)
goto fail;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
- peer_connector, peer_connector_len);
- signed_connector = os_malloc(peer_connector_len + 1);
- if (!signed_connector)
- goto fail;
- os_memcpy(signed_connector, peer_connector, peer_connector_len);
- signed_connector[peer_connector_len] = '\0';
-
- res = dpp_process_signed_connector(&info, csign, signed_connector);
+ res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
+ peer_connector, peer_connector_len);
if (res != DPP_STATUS_OK) {
ret = res;
goto fail;
@@ -6530,7 +3707,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
goto fail;
}
- if (!dpp_connector_match_groups(own_root, root)) {
+ if (!dpp_connector_match_groups(own_root, root, false)) {
wpa_printf(MSG_DEBUG,
"DPP: Peer connector does not include compatible group netrole with own connector");
ret = DPP_STATUS_NO_MATCH;
@@ -6598,1753 +3775,17 @@ fail:
if (ret != DPP_STATUS_OK)
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
- os_free(own_conn);
- os_free(signed_connector);
os_free(info.payload);
EVP_PKEY_free(own_key);
wpabuf_free(own_key_pub);
EVP_PKEY_free(peer_key);
- EVP_PKEY_free(csign);
json_free(root);
json_free(own_root);
return ret;
}
-static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
- int init)
-{
- EC_GROUP *group;
- size_t len = curve->prime_len;
- const u8 *x, *y;
- EVP_PKEY *res;
-
- switch (curve->ike_group) {
- case 19:
- x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
- y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
- break;
- case 20:
- x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
- y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
- break;
- case 21:
- x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
- y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
- break;
- case 28:
- x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
- y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
- break;
- case 29:
- x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
- y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
- break;
- case 30:
- x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
- y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
- break;
- default:
- return NULL;
- }
-
- group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
- if (!group)
- return NULL;
- res = dpp_set_pubkey_point_group(group, x, y, len);
- EC_GROUP_free(group);
- return res;
-}
-
-
-static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
- const u8 *mac_init, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group)
-{
- u8 hash[DPP_MAX_HASH_LEN];
- const u8 *addr[3];
- size_t len[3];
- unsigned int num_elem = 0;
- EC_POINT *Qi = NULL;
- EVP_PKEY *Pi = NULL;
- EC_KEY *Pi_ec = NULL;
- const EC_POINT *Pi_point;
- BIGNUM *hash_bn = NULL;
- const EC_GROUP *group = NULL;
- EC_GROUP *group2 = NULL;
-
- /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-
- wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
- addr[num_elem] = mac_init;
- len[num_elem] = ETH_ALEN;
- num_elem++;
- if (identifier) {
- wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
- identifier);
- addr[num_elem] = (const u8 *) identifier;
- len[num_elem] = os_strlen(identifier);
- num_elem++;
- }
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
- addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
- num_elem++;
- if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
- goto fail;
- wpa_hexdump_key(MSG_DEBUG,
- "DPP: H(MAC-Initiator | [identifier |] code)",
- hash, curve->hash_len);
- Pi = dpp_pkex_get_role_elem(curve, 1);
- if (!Pi)
- goto fail;
- dpp_debug_print_key("DPP: Pi", Pi);
- Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
- if (!Pi_ec)
- goto fail;
- Pi_point = EC_KEY_get0_public_key(Pi_ec);
-
- group = EC_KEY_get0_group(Pi_ec);
- if (!group)
- goto fail;
- group2 = EC_GROUP_dup(group);
- if (!group2)
- goto fail;
- Qi = EC_POINT_new(group2);
- if (!Qi) {
- EC_GROUP_free(group2);
- goto fail;
- }
- hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
- if (!hash_bn ||
- EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
- goto fail;
- if (EC_POINT_is_at_infinity(group, Qi)) {
- wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
- goto fail;
- }
- dpp_debug_print_point("DPP: Qi", group, Qi);
-out:
- EC_KEY_free(Pi_ec);
- EVP_PKEY_free(Pi);
- BN_clear_free(hash_bn);
- if (ret_group && Qi)
- *ret_group = group2;
- else
- EC_GROUP_free(group2);
- return Qi;
-fail:
- EC_POINT_free(Qi);
- Qi = NULL;
- goto out;
-}
-
-
-static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
- const u8 *mac_resp, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group)
-{
- u8 hash[DPP_MAX_HASH_LEN];
- const u8 *addr[3];
- size_t len[3];
- unsigned int num_elem = 0;
- EC_POINT *Qr = NULL;
- EVP_PKEY *Pr = NULL;
- EC_KEY *Pr_ec = NULL;
- const EC_POINT *Pr_point;
- BIGNUM *hash_bn = NULL;
- const EC_GROUP *group = NULL;
- EC_GROUP *group2 = NULL;
-
- /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
-
- wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
- addr[num_elem] = mac_resp;
- len[num_elem] = ETH_ALEN;
- num_elem++;
- if (identifier) {
- wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
- identifier);
- addr[num_elem] = (const u8 *) identifier;
- len[num_elem] = os_strlen(identifier);
- num_elem++;
- }
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
- addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
- num_elem++;
- if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
- goto fail;
- wpa_hexdump_key(MSG_DEBUG,
- "DPP: H(MAC-Responder | [identifier |] code)",
- hash, curve->hash_len);
- Pr = dpp_pkex_get_role_elem(curve, 0);
- if (!Pr)
- goto fail;
- dpp_debug_print_key("DPP: Pr", Pr);
- Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
- if (!Pr_ec)
- goto fail;
- Pr_point = EC_KEY_get0_public_key(Pr_ec);
-
- group = EC_KEY_get0_group(Pr_ec);
- if (!group)
- goto fail;
- group2 = EC_GROUP_dup(group);
- if (!group2)
- goto fail;
- Qr = EC_POINT_new(group2);
- if (!Qr) {
- EC_GROUP_free(group2);
- goto fail;
- }
- hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
- if (!hash_bn ||
- EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
- goto fail;
- if (EC_POINT_is_at_infinity(group, Qr)) {
- wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
- goto fail;
- }
- dpp_debug_print_point("DPP: Qr", group, Qr);
-out:
- EC_KEY_free(Pr_ec);
- EVP_PKEY_free(Pr);
- BN_clear_free(hash_bn);
- if (ret_group && Qr)
- *ret_group = group2;
- else
- EC_GROUP_free(group2);
- return Qr;
-fail:
- EC_POINT_free(Qr);
- Qr = NULL;
- goto out;
-}
-
-
-#ifdef CONFIG_TESTING_OPTIONS
-static int dpp_test_gen_invalid_key(struct wpabuf *msg,
- const struct dpp_curve_params *curve)
-{
- BN_CTX *ctx;
- BIGNUM *x, *y;
- int ret = -1;
- EC_GROUP *group;
- EC_POINT *point;
-
- group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
- if (!group)
- return -1;
-
- ctx = BN_CTX_new();
- point = EC_POINT_new(group);
- x = BN_new();
- y = BN_new();
- if (!ctx || !point || !x || !y)
- goto fail;
-
- if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
- goto fail;
-
- /* Generate a random y coordinate that results in a point that is not
- * on the curve. */
- for (;;) {
- if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
- goto fail;
-
- if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
- ctx) != 1) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
- /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
- * return an error from EC_POINT_set_affine_coordinates_GFp()
- * when the point is not on the curve. */
- break;
-#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
- goto fail;
-#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx))
- break;
- }
-
- if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
- goto fail;
-
- ret = 0;
-fail:
- if (ret < 0)
- wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
- BN_free(x);
- BN_free(y);
- EC_POINT_free(point);
- BN_CTX_free(ctx);
- EC_GROUP_free(group);
-
- return ret;
-}
-#endif /* CONFIG_TESTING_OPTIONS */
-
-
-static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
-{
- EC_KEY *X_ec = NULL;
- const EC_POINT *X_point;
- BN_CTX *bnctx = NULL;
- EC_GROUP *group = NULL;
- EC_POINT *Qi = NULL, *M = NULL;
- struct wpabuf *M_buf = NULL;
- BIGNUM *Mx = NULL, *My = NULL;
- struct wpabuf *msg = NULL;
- size_t attr_len;
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
-
- wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
-
- /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
- Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
- pkex->identifier, bnctx, &group);
- if (!Qi)
- goto fail;
-
- /* Generate a random ephemeral keypair x/X */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_pkex_ephemeral_key_override_len) {
- const struct dpp_curve_params *tmp_curve;
-
- wpa_printf(MSG_INFO,
- "DPP: TESTING - override ephemeral key x/X");
- pkex->x = dpp_set_keypair(&tmp_curve,
- dpp_pkex_ephemeral_key_override,
- dpp_pkex_ephemeral_key_override_len);
- } else {
- pkex->x = dpp_gen_keypair(curve);
- }
-#else /* CONFIG_TESTING_OPTIONS */
- pkex->x = dpp_gen_keypair(curve);
-#endif /* CONFIG_TESTING_OPTIONS */
- if (!pkex->x)
- goto fail;
-
- /* M = X + Qi */
- X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
- if (!X_ec)
- goto fail;
- X_point = EC_KEY_get0_public_key(X_ec);
- if (!X_point)
- goto fail;
- dpp_debug_print_point("DPP: X", group, X_point);
- M = EC_POINT_new(group);
- Mx = BN_new();
- My = BN_new();
- if (!M || !Mx || !My ||
- EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
- goto fail;
- dpp_debug_print_point("DPP: M", group, M);
-
- /* Initiator -> Responder: group, [identifier,] M */
- attr_len = 4 + 2;
- if (pkex->identifier)
- attr_len += 4 + os_strlen(pkex->identifier);
- attr_len += 4 + 2 * curve->prime_len;
- msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
- if (!msg)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
- goto skip_finite_cyclic_group;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Finite Cyclic Group attribute */
- wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
- wpabuf_put_le16(msg, 2);
- wpabuf_put_le16(msg, curve->ike_group);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_finite_cyclic_group:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Code Identifier attribute */
- if (pkex->identifier) {
- wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
- wpabuf_put_le16(msg, os_strlen(pkex->identifier));
- wpabuf_put_str(msg, pkex->identifier);
- }
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
- goto out;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* M in Encrypted Key attribute */
- wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
- wpabuf_put_le16(msg, 2 * curve->prime_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
- if (dpp_test_gen_invalid_key(msg, curve) < 0)
- goto fail;
- goto out;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
- goto fail;
-
-out:
- wpabuf_free(M_buf);
- EC_KEY_free(X_ec);
- EC_POINT_free(M);
- EC_POINT_free(Qi);
- BN_clear_free(Mx);
- BN_clear_free(My);
- BN_CTX_free(bnctx);
- EC_GROUP_free(group);
- return msg;
-fail:
- wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
- wpabuf_free(msg);
- msg = NULL;
- goto out;
-}
-
-
-static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
-{
- wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
-}
-
-
-struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
- const u8 *own_mac,
- const char *identifier,
- const char *code)
-{
- struct dpp_pkex *pkex;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
- wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
- MAC2STR(dpp_pkex_own_mac_override));
- own_mac = dpp_pkex_own_mac_override;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- pkex = os_zalloc(sizeof(*pkex));
- if (!pkex)
- return NULL;
- pkex->msg_ctx = msg_ctx;
- pkex->initiator = 1;
- pkex->own_bi = bi;
- os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
- if (identifier) {
- pkex->identifier = os_strdup(identifier);
- if (!pkex->identifier)
- goto fail;
- }
- pkex->code = os_strdup(code);
- if (!pkex->code)
- goto fail;
- pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
- if (!pkex->exchange_req)
- goto fail;
- return pkex;
-fail:
- dpp_pkex_free(pkex);
- return NULL;
-}
-
-
-static struct wpabuf *
-dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
- enum dpp_status_error status,
- const BIGNUM *Nx, const BIGNUM *Ny)
-{
- struct wpabuf *msg = NULL;
- size_t attr_len;
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
-
- /* Initiator -> Responder: DPP Status, [identifier,] N */
- attr_len = 4 + 1;
- if (pkex->identifier)
- attr_len += 4 + os_strlen(pkex->identifier);
- attr_len += 4 + 2 * curve->prime_len;
- msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
- if (!msg)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
- goto skip_status;
- }
-
- if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
- status = 255;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* DPP Status */
- dpp_build_attr_status(msg, status);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_status:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Code Identifier attribute */
- if (pkex->identifier) {
- wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
- wpabuf_put_le16(msg, os_strlen(pkex->identifier));
- wpabuf_put_str(msg, pkex->identifier);
- }
-
- if (status != DPP_STATUS_OK)
- goto skip_encrypted_key;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
- goto skip_encrypted_key;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* N in Encrypted Key attribute */
- wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
- wpabuf_put_le16(msg, 2 * curve->prime_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
- if (dpp_test_gen_invalid_key(msg, curve) < 0)
- goto fail;
- goto skip_encrypted_key;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
- goto fail;
-
-skip_encrypted_key:
- if (status == DPP_STATUS_BAD_GROUP) {
- /* Finite Cyclic Group attribute */
- wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
- wpabuf_put_le16(msg, 2);
- wpabuf_put_le16(msg, curve->ike_group);
- }
-
- return msg;
-fail:
- wpabuf_free(msg);
- return NULL;
-}
-
-
-static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
- const u8 *Mx, size_t Mx_len,
- const u8 *Nx, size_t Nx_len,
- const char *code,
- const u8 *Kx, size_t Kx_len,
- u8 *z, unsigned int hash_len)
-{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- int res;
- u8 *info, *pos;
- size_t info_len;
-
- /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
- */
-
- /* HKDF-Extract(<>, IKM=K.x) */
- os_memset(salt, 0, hash_len);
- if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
- prk, hash_len);
- info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
- info = os_malloc(info_len);
- if (!info)
- return -1;
- pos = info;
- os_memcpy(pos, mac_init, ETH_ALEN);
- pos += ETH_ALEN;
- os_memcpy(pos, mac_resp, ETH_ALEN);
- pos += ETH_ALEN;
- os_memcpy(pos, Mx, Mx_len);
- pos += Mx_len;
- os_memcpy(pos, Nx, Nx_len);
- pos += Nx_len;
- os_memcpy(pos, code, os_strlen(code));
-
- /* HKDF-Expand(PRK, info, L) */
- if (hash_len == 32)
- res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
- z, hash_len);
- else if (hash_len == 48)
- res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
- z, hash_len);
- else if (hash_len == 64)
- res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
- z, hash_len);
- else
- res = -1;
- os_free(info);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
- z, hash_len);
- return 0;
-}
-
-
-static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
- const char *identifier)
-{
- if (!attr_id && identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: No PKEX code identifier received, but expected one");
- return 0;
- }
-
- if (attr_id && !identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: PKEX code identifier received, but not expecting one");
- return 0;
- }
-
- if (attr_id && identifier &&
- (os_strlen(identifier) != attr_id_len ||
- os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
- wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
- return 0;
- }
-
- return 1;
-}
-
-
-struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
- struct dpp_bootstrap_info *bi,
- const u8 *own_mac,
- const u8 *peer_mac,
- const char *identifier,
- const char *code,
- const u8 *buf, size_t len)
-{
- const u8 *attr_group, *attr_id, *attr_key;
- u16 attr_group_len, attr_id_len, attr_key_len;
- const struct dpp_curve_params *curve = bi->curve;
- u16 ike_group;
- struct dpp_pkex *pkex = NULL;
- EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
- BN_CTX *bnctx = NULL;
- EC_GROUP *group = NULL;
- BIGNUM *Mx = NULL, *My = NULL;
- EC_KEY *Y_ec = NULL, *X_ec = NULL;;
- const EC_POINT *Y_point;
- BIGNUM *Nx = NULL, *Ny = NULL;
- u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
- size_t Kx_len;
- int res;
-
- if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "PKEX counter t limit reached - ignore message");
- return NULL;
- }
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
- wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
- MAC2STR(dpp_pkex_peer_mac_override));
- peer_mac = dpp_pkex_peer_mac_override;
- }
- if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
- wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
- MAC2STR(dpp_pkex_own_mac_override));
- own_mac = dpp_pkex_own_mac_override;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- attr_id_len = 0;
- attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
- &attr_id_len);
- if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
- return NULL;
-
- attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
- &attr_group_len);
- if (!attr_group || attr_group_len != 2) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Missing or invalid Finite Cyclic Group attribute");
- return NULL;
- }
- ike_group = WPA_GET_LE16(attr_group);
- if (ike_group != curve->ike_group) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Mismatching PKEX curve: peer=%u own=%u",
- ike_group, curve->ike_group);
- pkex = os_zalloc(sizeof(*pkex));
- if (!pkex)
- goto fail;
- pkex->own_bi = bi;
- pkex->failed = 1;
- pkex->exchange_resp = dpp_pkex_build_exchange_resp(
- pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
- if (!pkex->exchange_resp)
- goto fail;
- return pkex;
- }
-
- /* M in Encrypted Key attribute */
- attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
- &attr_key_len);
- if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
- attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Missing Encrypted Key attribute");
- return NULL;
- }
-
- /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
- Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
- &group);
- if (!Qi)
- goto fail;
-
- /* X' = M - Qi */
- X = EC_POINT_new(group);
- M = EC_POINT_new(group);
- Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
- My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
- if (!X || !M || !Mx || !My ||
- EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, M) ||
- !EC_POINT_is_on_curve(group, M, bnctx) ||
- EC_POINT_invert(group, Qi, bnctx) != 1 ||
- EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, X) ||
- !EC_POINT_is_on_curve(group, X, bnctx)) {
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Invalid Encrypted Key value");
- bi->pkex_t++;
- goto fail;
- }
- dpp_debug_print_point("DPP: M", group, M);
- dpp_debug_print_point("DPP: X'", group, X);
-
- pkex = os_zalloc(sizeof(*pkex));
- if (!pkex)
- goto fail;
- pkex->t = bi->pkex_t;
- pkex->msg_ctx = msg_ctx;
- pkex->own_bi = bi;
- os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
- os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
- if (identifier) {
- pkex->identifier = os_strdup(identifier);
- if (!pkex->identifier)
- goto fail;
- }
- pkex->code = os_strdup(code);
- if (!pkex->code)
- goto fail;
-
- os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
-
- X_ec = EC_KEY_new();
- if (!X_ec ||
- EC_KEY_set_group(X_ec, group) != 1 ||
- EC_KEY_set_public_key(X_ec, X) != 1)
- goto fail;
- pkex->x = EVP_PKEY_new();
- if (!pkex->x ||
- EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
- goto fail;
-
- /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
- Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
- if (!Qr)
- goto fail;
-
- /* Generate a random ephemeral keypair y/Y */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_pkex_ephemeral_key_override_len) {
- const struct dpp_curve_params *tmp_curve;
-
- wpa_printf(MSG_INFO,
- "DPP: TESTING - override ephemeral key y/Y");
- pkex->y = dpp_set_keypair(&tmp_curve,
- dpp_pkex_ephemeral_key_override,
- dpp_pkex_ephemeral_key_override_len);
- } else {
- pkex->y = dpp_gen_keypair(curve);
- }
-#else /* CONFIG_TESTING_OPTIONS */
- pkex->y = dpp_gen_keypair(curve);
-#endif /* CONFIG_TESTING_OPTIONS */
- if (!pkex->y)
- goto fail;
-
- /* N = Y + Qr */
- Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
- if (!Y_ec)
- goto fail;
- Y_point = EC_KEY_get0_public_key(Y_ec);
- if (!Y_point)
- goto fail;
- dpp_debug_print_point("DPP: Y", group, Y_point);
- N = EC_POINT_new(group);
- Nx = BN_new();
- Ny = BN_new();
- if (!N || !Nx || !Ny ||
- EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
- goto fail;
- dpp_debug_print_point("DPP: N", group, N);
-
- pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
- Nx, Ny);
- if (!pkex->exchange_resp)
- goto fail;
-
- /* K = y * X' */
- if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
- Kx, Kx_len);
-
- /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
- */
- res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
- pkex->Mx, curve->prime_len,
- pkex->Nx, curve->prime_len, pkex->code,
- Kx, Kx_len, pkex->z, curve->hash_len);
- os_memset(Kx, 0, Kx_len);
- if (res < 0)
- goto fail;
-
- pkex->exchange_done = 1;
-
-out:
- BN_CTX_free(bnctx);
- EC_POINT_free(Qi);
- EC_POINT_free(Qr);
- BN_free(Mx);
- BN_free(My);
- BN_free(Nx);
- BN_free(Ny);
- EC_POINT_free(M);
- EC_POINT_free(N);
- EC_POINT_free(X);
- EC_KEY_free(X_ec);
- EC_KEY_free(Y_ec);
- EC_GROUP_free(group);
- return pkex;
-fail:
- wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
- dpp_pkex_free(pkex);
- pkex = NULL;
- goto out;
-}
-
-
-static struct wpabuf *
-dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
- const struct wpabuf *A_pub, const u8 *u)
-{
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
- struct wpabuf *msg = NULL;
- size_t clear_len, attr_len;
- struct wpabuf *clear = NULL;
- u8 *wrapped;
- u8 octet;
- const u8 *addr[2];
- size_t len[2];
-
- /* {A, u, [bootstrapping info]}z */
- clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
- clear = wpabuf_alloc(clear_len);
- attr_len = 4 + clear_len + AES_BLOCK_SIZE;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
- if (!clear || !msg)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
- goto skip_bootstrap_key;
- }
- if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, 2 * curve->prime_len);
- if (dpp_test_gen_invalid_key(clear, curve) < 0)
- goto fail;
- goto skip_bootstrap_key;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* A in Bootstrap Key attribute */
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, wpabuf_len(A_pub));
- wpabuf_put_buf(clear, A_pub);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_bootstrap_key:
- if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
- goto skip_i_auth_tag;
- }
- if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
- wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
- wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, u, curve->hash_len - 1);
- wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
- goto skip_i_auth_tag;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* u in I-Auth tag attribute */
- wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
- wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, u, curve->hash_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_i_auth_tag:
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = DPP_HDR_LEN;
- octet = 0;
- addr[1] = &octet;
- len[1] = sizeof(octet);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
- wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
-
- wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
- if (aes_siv_encrypt(pkex->z, curve->hash_len,
- wpabuf_head(clear), wpabuf_len(clear),
- 2, addr, len, wrapped) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
-out:
- wpabuf_free(clear);
- return msg;
-
-fail:
- wpabuf_free(msg);
- msg = NULL;
- goto out;
-}
-
-
-struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
- const u8 *peer_mac,
- const u8 *buf, size_t buflen)
-{
- const u8 *attr_status, *attr_id, *attr_key, *attr_group;
- u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
- EC_GROUP *group = NULL;
- BN_CTX *bnctx = NULL;
- struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
- EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
- BIGNUM *Nx = NULL, *Ny = NULL;
- EC_KEY *Y_ec = NULL;
- size_t Jx_len, Kx_len;
- u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
- const u8 *addr[4];
- size_t len[4];
- u8 u[DPP_MAX_HASH_LEN];
- int res;
-
- if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
- return NULL;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at PKEX Exchange Response");
- pkex->failed = 1;
- return NULL;
- }
-
- if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
- wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
- MAC2STR(dpp_pkex_peer_mac_override));
- peer_mac = dpp_pkex_peer_mac_override;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
-
- attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
- &attr_status_len);
- if (!attr_status || attr_status_len != 1) {
- dpp_pkex_fail(pkex, "No DPP Status attribute");
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
-
- if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
- attr_group = dpp_get_attr(buf, buflen,
- DPP_ATTR_FINITE_CYCLIC_GROUP,
- &attr_group_len);
- if (attr_group && attr_group_len == 2) {
- wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
- "Peer indicated mismatching PKEX group - proposed %u",
- WPA_GET_LE16(attr_group));
- return NULL;
- }
- }
-
- if (attr_status[0] != DPP_STATUS_OK) {
- dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
- return NULL;
- }
-
- attr_id_len = 0;
- attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
- &attr_id_len);
- if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
- pkex->identifier)) {
- dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
- return NULL;
- }
-
- /* N in Encrypted Key attribute */
- attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
- &attr_key_len);
- if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
- dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
- return NULL;
- }
-
- /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
- Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
- pkex->identifier, bnctx, &group);
- if (!Qr)
- goto fail;
-
- /* Y' = N - Qr */
- Y = EC_POINT_new(group);
- N = EC_POINT_new(group);
- Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
- Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
- if (!Y || !N || !Nx || !Ny ||
- EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, N) ||
- !EC_POINT_is_on_curve(group, N, bnctx) ||
- EC_POINT_invert(group, Qr, bnctx) != 1 ||
- EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, Y) ||
- !EC_POINT_is_on_curve(group, Y, bnctx)) {
- dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
- pkex->t++;
- goto fail;
- }
- dpp_debug_print_point("DPP: N", group, N);
- dpp_debug_print_point("DPP: Y'", group, Y);
-
- pkex->exchange_done = 1;
-
- /* ECDH: J = a * Y’ */
- Y_ec = EC_KEY_new();
- if (!Y_ec ||
- EC_KEY_set_group(Y_ec, group) != 1 ||
- EC_KEY_set_public_key(Y_ec, Y) != 1)
- goto fail;
- pkex->y = EVP_PKEY_new();
- if (!pkex->y ||
- EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
- goto fail;
- if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
- Jx, Jx_len);
-
- /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
- A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
- if (!A_pub || !Y_pub || !X_pub)
- goto fail;
- addr[0] = pkex->own_mac;
- len[0] = ETH_ALEN;
- addr[1] = wpabuf_head(A_pub);
- len[1] = wpabuf_len(A_pub) / 2;
- addr[2] = wpabuf_head(Y_pub);
- len[2] = wpabuf_len(Y_pub) / 2;
- addr[3] = wpabuf_head(X_pub);
- len[3] = wpabuf_len(X_pub) / 2;
- if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
-
- /* K = x * Y’ */
- if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
- Kx, Kx_len);
-
- /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
- */
- res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
- pkex->Mx, curve->prime_len,
- attr_key /* N.x */, attr_key_len / 2,
- pkex->code, Kx, Kx_len,
- pkex->z, curve->hash_len);
- os_memset(Kx, 0, Kx_len);
- if (res < 0)
- goto fail;
-
- msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
- if (!msg)
- goto fail;
-
-out:
- wpabuf_free(A_pub);
- wpabuf_free(X_pub);
- wpabuf_free(Y_pub);
- EC_POINT_free(Qr);
- EC_POINT_free(Y);
- EC_POINT_free(N);
- BN_free(Nx);
- BN_free(Ny);
- EC_KEY_free(Y_ec);
- BN_CTX_free(bnctx);
- EC_GROUP_free(group);
- return msg;
-fail:
- wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
- goto out;
-}
-
-
-static struct wpabuf *
-dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
- const struct wpabuf *B_pub, const u8 *v)
-{
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
- struct wpabuf *msg = NULL;
- const u8 *addr[2];
- size_t len[2];
- u8 octet;
- u8 *wrapped;
- struct wpabuf *clear = NULL;
- size_t clear_len, attr_len;
-
- /* {B, v [bootstrapping info]}z */
- clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
- clear = wpabuf_alloc(clear_len);
- attr_len = 4 + clear_len + AES_BLOCK_SIZE;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
- if (!clear || !msg)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
- goto skip_bootstrap_key;
- }
- if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, 2 * curve->prime_len);
- if (dpp_test_gen_invalid_key(clear, curve) < 0)
- goto fail;
- goto skip_bootstrap_key;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* B in Bootstrap Key attribute */
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, wpabuf_len(B_pub));
- wpabuf_put_buf(clear, B_pub);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_bootstrap_key:
- if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
- goto skip_r_auth_tag;
- }
- if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
- wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
- wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, v, curve->hash_len - 1);
- wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
- goto skip_r_auth_tag;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* v in R-Auth tag attribute */
- wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
- wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, v, curve->hash_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_r_auth_tag:
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = DPP_HDR_LEN;
- octet = 1;
- addr[1] = &octet;
- len[1] = sizeof(octet);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
- wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
-
- wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
- if (aes_siv_encrypt(pkex->z, curve->hash_len,
- wpabuf_head(clear), wpabuf_len(clear),
- 2, addr, len, wrapped) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
-out:
- wpabuf_free(clear);
- return msg;
-
-fail:
- wpabuf_free(msg);
- msg = NULL;
- goto out;
-}
-
-
-struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
- const u8 *hdr,
- const u8 *buf, size_t buflen)
-{
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
- size_t Jx_len, Lx_len;
- u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
- u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
- const u8 *wrapped_data, *b_key, *peer_u;
- u16 wrapped_data_len, b_key_len, peer_u_len = 0;
- const u8 *addr[4];
- size_t len[4];
- u8 octet;
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
- struct wpabuf *B_pub = NULL;
- u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at PKEX CR Request");
- pkex->failed = 1;
- return NULL;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (!pkex->exchange_done || pkex->failed ||
- pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
- goto fail;
-
- wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- dpp_pkex_fail(pkex,
- "Missing or invalid required Wrapped Data attribute");
- goto fail;
- }
-
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- goto fail;
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- octet = 0;
- addr[1] = &octet;
- len[1] = sizeof(octet);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- if (aes_siv_decrypt(pkex->z, curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_pkex_fail(pkex,
- "AES-SIV decryption failed - possible PKEX code mismatch");
- pkex->failed = 1;
- pkex->t++;
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
- &b_key_len);
- if (!b_key || b_key_len != 2 * curve->prime_len) {
- dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
- goto fail;
- }
- pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
- b_key_len);
- if (!pkex->peer_bootstrap_key) {
- dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
- goto fail;
- }
- dpp_debug_print_key("DPP: Peer bootstrap public key",
- pkex->peer_bootstrap_key);
-
- /* ECDH: J' = y * A' */
- if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
- Jx, Jx_len);
-
- /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
- A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
- if (!A_pub || !Y_pub || !X_pub)
- goto fail;
- addr[0] = pkex->peer_mac;
- len[0] = ETH_ALEN;
- addr[1] = wpabuf_head(A_pub);
- len[1] = wpabuf_len(A_pub) / 2;
- addr[2] = wpabuf_head(Y_pub);
- len[2] = wpabuf_len(Y_pub) / 2;
- addr[3] = wpabuf_head(X_pub);
- len[3] = wpabuf_len(X_pub) / 2;
- if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
- goto fail;
-
- peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
- &peer_u_len);
- if (!peer_u || peer_u_len != curve->hash_len ||
- os_memcmp(peer_u, u, curve->hash_len) != 0) {
- dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
- wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
- u, curve->hash_len);
- wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
- pkex->t++;
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
-
- /* ECDH: L = b * X' */
- if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
- Lx, Lx_len);
-
- /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
- B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
- if (!B_pub)
- goto fail;
- addr[0] = pkex->own_mac;
- len[0] = ETH_ALEN;
- addr[1] = wpabuf_head(B_pub);
- len[1] = wpabuf_len(B_pub) / 2;
- addr[2] = wpabuf_head(X_pub);
- len[2] = wpabuf_len(X_pub) / 2;
- addr[3] = wpabuf_head(Y_pub);
- len[3] = wpabuf_len(Y_pub) / 2;
- if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
-
- msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
- if (!msg)
- goto fail;
-
-out:
- os_free(unwrapped);
- wpabuf_free(A_pub);
- wpabuf_free(B_pub);
- wpabuf_free(X_pub);
- wpabuf_free(Y_pub);
- return msg;
-fail:
- wpa_printf(MSG_DEBUG,
- "DPP: PKEX Commit-Reveal Request processing failed");
- goto out;
-}
-
-
-int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
- const u8 *buf, size_t buflen)
-{
- const struct dpp_curve_params *curve = pkex->own_bi->curve;
- const u8 *wrapped_data, *b_key, *peer_v;
- u16 wrapped_data_len, b_key_len, peer_v_len = 0;
- const u8 *addr[4];
- size_t len[4];
- u8 octet;
- u8 *unwrapped = NULL;
- size_t unwrapped_len = 0;
- int ret = -1;
- u8 v[DPP_MAX_HASH_LEN];
- size_t Lx_len;
- u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
- struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at PKEX CR Response");
- pkex->failed = 1;
- goto fail;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (!pkex->exchange_done || pkex->failed ||
- pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
- goto fail;
-
- wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- dpp_pkex_fail(pkex,
- "Missing or invalid required Wrapped Data attribute");
- goto fail;
- }
-
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, wrapped_data_len);
- unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
- unwrapped = os_malloc(unwrapped_len);
- if (!unwrapped)
- goto fail;
-
- addr[0] = hdr;
- len[0] = DPP_HDR_LEN;
- octet = 1;
- addr[1] = &octet;
- len[1] = sizeof(octet);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- if (aes_siv_decrypt(pkex->z, curve->hash_len,
- wrapped_data, wrapped_data_len,
- 2, addr, len, unwrapped) < 0) {
- dpp_pkex_fail(pkex,
- "AES-SIV decryption failed - possible PKEX code mismatch");
- pkex->t++;
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
- unwrapped, unwrapped_len);
-
- if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
- goto fail;
- }
-
- b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
- &b_key_len);
- if (!b_key || b_key_len != 2 * curve->prime_len) {
- dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
- goto fail;
- }
- pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
- b_key_len);
- if (!pkex->peer_bootstrap_key) {
- dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
- goto fail;
- }
- dpp_debug_print_key("DPP: Peer bootstrap public key",
- pkex->peer_bootstrap_key);
-
- /* ECDH: L' = x * B' */
- if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
- goto fail;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
- Lx, Lx_len);
-
- /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
- B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
- if (!B_pub || !X_pub || !Y_pub)
- goto fail;
- addr[0] = pkex->peer_mac;
- len[0] = ETH_ALEN;
- addr[1] = wpabuf_head(B_pub);
- len[1] = wpabuf_len(B_pub) / 2;
- addr[2] = wpabuf_head(X_pub);
- len[2] = wpabuf_len(X_pub) / 2;
- addr[3] = wpabuf_head(Y_pub);
- len[3] = wpabuf_len(Y_pub) / 2;
- if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
- goto fail;
-
- peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
- &peer_v_len);
- if (!peer_v || peer_v_len != curve->hash_len ||
- os_memcmp(peer_v, v, curve->hash_len) != 0) {
- dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
- wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
- v, curve->hash_len);
- wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
- pkex->t++;
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
-
- ret = 0;
-out:
- wpabuf_free(B_pub);
- wpabuf_free(X_pub);
- wpabuf_free(Y_pub);
- os_free(unwrapped);
- return ret;
-fail:
- goto out;
-}
-
-
-void dpp_pkex_free(struct dpp_pkex *pkex)
-{
- if (!pkex)
- return;
-
- os_free(pkex->identifier);
- os_free(pkex->code);
- EVP_PKEY_free(pkex->x);
- EVP_PKEY_free(pkex->y);
- EVP_PKEY_free(pkex->peer_bootstrap_key);
- wpabuf_free(pkex->exchange_req);
- wpabuf_free(pkex->exchange_resp);
- os_free(pkex);
-}
-
-
-#ifdef CONFIG_TESTING_OPTIONS
-char * dpp_corrupt_connector_signature(const char *connector)
-{
- char *tmp, *pos, *signed3 = NULL;
- unsigned char *signature = NULL;
- size_t signature_len = 0, signed3_len;
-
- tmp = os_zalloc(os_strlen(connector) + 5);
- if (!tmp)
- goto fail;
- os_memcpy(tmp, connector, os_strlen(connector));
-
- pos = os_strchr(tmp, '.');
- if (!pos)
- goto fail;
-
- pos = os_strchr(pos + 1, '.');
- if (!pos)
- goto fail;
- pos++;
-
- wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
- pos);
- signature = base64_url_decode((const unsigned char *) pos,
- os_strlen(pos), &signature_len);
- if (!signature || signature_len == 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
- signature, signature_len);
- signature[signature_len - 1] ^= 0x01;
- wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
- signature, signature_len);
- signed3 = (char *) base64_url_encode(signature, signature_len,
- &signed3_len, 0);
- if (!signed3)
- goto fail;
- os_memcpy(pos, signed3, signed3_len);
- pos[signed3_len] = '\0';
- wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
- pos);
-
-out:
- os_free(signature);
- os_free(signed3);
- return tmp;
-fail:
- os_free(tmp);
- tmp = NULL;
- goto out;
-}
-#endif /* CONFIG_TESTING_OPTIONS */
-
-
-#ifdef CONFIG_DPP2
-
-struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
- size_t net_access_key_len)
-{
- struct wpabuf *pub = NULL;
- EVP_PKEY *own_key;
- struct dpp_pfs *pfs;
-
- pfs = os_zalloc(sizeof(*pfs));
- if (!pfs)
- return NULL;
-
- own_key = dpp_set_keypair(&pfs->curve, net_access_key,
- net_access_key_len);
- if (!own_key) {
- wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
- goto fail;
- }
- EVP_PKEY_free(own_key);
-
- pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
- if (!pfs->ecdh)
- goto fail;
-
- pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
- pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
- if (!pub)
- goto fail;
-
- pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
- if (!pfs->ie)
- goto fail;
- wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
- wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
- wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
- wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
- wpabuf_put_buf(pfs->ie, pub);
- wpabuf_free(pub);
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
- pfs->ie);
-
- return pfs;
-fail:
- wpabuf_free(pub);
- dpp_pfs_free(pfs);
- return NULL;
-}
-
-
-int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
-{
- if (peer_ie_len < 2)
- return -1;
- if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
- wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
- return -1;
- }
-
- pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
- peer_ie_len - 2);
- pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
- if (!pfs->secret) {
- wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
- return -1;
- }
- wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
- return 0;
-}
-
-
-void dpp_pfs_free(struct dpp_pfs *pfs)
-{
- if (!pfs)
- return;
- crypto_ecdh_deinit(pfs->ecdh);
- wpabuf_free(pfs->ie);
- wpabuf_clear_free(pfs->secret);
- os_free(pfs);
-}
-
-#endif /* CONFIG_DPP2 */
-
-
-static unsigned int dpp_next_id(struct dpp_global *dpp)
+unsigned int dpp_next_id(struct dpp_global *dpp)
{
struct dpp_bootstrap_info *bi;
unsigned int max_id = 0;
@@ -8370,6 +3811,10 @@ static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
if (id && bi->id != id)
continue;
found = 1;
+#ifdef CONFIG_DPP2
+ if (dpp->remove_bi)
+ dpp->remove_bi(dpp->cb_ctx, bi);
+#endif /* CONFIG_DPP2 */
dl_list_del(&bi->list);
dpp_bootstrap_info_free(bi);
}
@@ -8388,10 +3833,30 @@ struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
if (!dpp)
return NULL;
- bi = dpp_parse_qr_code(uri);
+ bi = dpp_parse_uri(uri);
+ if (!bi)
+ return NULL;
+
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
+ const char *uri)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ bi = dpp_parse_uri(uri);
if (!bi)
return NULL;
+ bi->type = DPP_BOOTSTRAP_NFC_URI;
bi->id = dpp_next_id(dpp);
dl_list_add(&dpp->bootstrap, &bi->list);
return bi;
@@ -8400,11 +3865,10 @@ struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+ char *mac = NULL, *info = NULL, *curve = NULL;
char *key = NULL;
u8 *privkey = NULL;
size_t privkey_len = 0;
- size_t len;
int ret = -1;
struct dpp_bootstrap_info *bi;
@@ -8419,10 +3883,12 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
bi->type = DPP_BOOTSTRAP_QR_CODE;
else if (os_strstr(cmd, "type=pkex"))
bi->type = DPP_BOOTSTRAP_PKEX;
+ else if (os_strstr(cmd, "type=nfc-uri"))
+ bi->type = DPP_BOOTSTRAP_NFC_URI;
else
goto fail;
- chan = get_param(cmd, " chan=");
+ bi->chan = get_param(cmd, " chan=");
mac = get_param(cmd, " mac=");
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
@@ -8436,43 +3902,19 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
goto fail;
}
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
+ if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
+ dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
+ dpp_parse_uri_mac(bi, mac) < 0 ||
+ dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_gen_uri(bi) < 0)
goto fail;
- len = 4; /* "DPP:" */
- if (chan) {
- if (dpp_parse_uri_chan_list(bi, chan) < 0)
- goto fail;
- len += 3 + os_strlen(chan); /* C:...; */
- }
- if (mac) {
- if (dpp_parse_uri_mac(bi, mac) < 0)
- goto fail;
- len += 3 + os_strlen(mac); /* M:...; */
- }
- if (info) {
- if (dpp_parse_uri_info(bi, info) < 0)
- goto fail;
- len += 3 + os_strlen(info); /* I:...; */
- }
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
- chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
- mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
- info ? "I:" : "", info ? info : "", info ? ";" : "",
- pk);
bi->id = dpp_next_id(dpp);
dl_list_add(&dpp->bootstrap, &bi->list);
ret = bi->id;
bi = NULL;
fail:
os_free(curve);
- os_free(pk);
- os_free(chan);
os_free(mac);
os_free(info);
str_clear_free(key);
@@ -8514,33 +3956,6 @@ int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
}
-struct dpp_bootstrap_info *
-dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
- unsigned int freq)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- return NULL;
- bi->id = dpp_next_id(dpp);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, peer, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = pkex->own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return NULL;
- }
- dpp_pkex_free(pkex);
- dl_list_add(&dpp->bootstrap, &bi->list);
- return bi;
-}
-
-
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
{
struct dpp_bootstrap_info *bi;
@@ -8567,14 +3982,38 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id,
"mac_addr=" MACSTR "\n"
"info=%s\n"
"num_freq=%u\n"
+ "use_freq=%u\n"
"curve=%s\n"
- "pkhash=%s\n",
+ "pkhash=%s\n"
+ "version=%d\n",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
bi->num_freq,
+ bi->num_freq == 1 ? bi->freq[0] : 0,
bi->curve->name,
- pkhash);
+ pkhash,
+ bi->version);
+}
+
+
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return -1;
+
+ str_clear_free(bi->configurator_params);
+
+ if (params) {
+ bi->configurator_params = os_strdup(params);
+ return bi->configurator_params ? 0 : -1;
+ }
+
+ bi->configurator_params = NULL;
+ return 0;
}
@@ -8610,7 +4049,108 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
if (*own_bi && *peer_bi)
break;
}
+}
+
+
+#ifdef CONFIG_DPP2
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
+ SHA256_MAC_LEN) == 0)
+ return bi;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_DPP2 */
+
+
+static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ unsigned int i, freq = 0;
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+ char chan[20];
+
+ if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
+ return 0; /* no channel preference/constraint */
+
+ for (i = 0; i < peer_bi->num_freq; i++) {
+ if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
+ freq_included(own_bi->freq, own_bi->num_freq,
+ peer_bi->freq[i])) {
+ freq = peer_bi->freq[i];
+ break;
+ }
+ }
+ if (!freq) {
+ wpa_printf(MSG_DEBUG, "DPP: No common channel found");
+ return -1;
+ }
+
+ mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not determine operating class or channel number for %u MHz",
+ freq);
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
+ freq, op_class, channel);
+ os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
+ os_free(own_bi->chan);
+ own_bi->chan = os_strdup(chan);
+ own_bi->freq[0] = freq;
+ own_bi->num_freq = 1;
+ os_free(peer_bi->chan);
+ peer_bi->chan = os_strdup(chan);
+ peer_bi->freq[0] = freq;
+ peer_bi->num_freq = 1;
+
+ return dpp_gen_uri(own_bi);
+}
+
+
+static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (peer_bi->curve == own_bi->curve)
+ return 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update own bootstrapping key to match peer curve from NFC handover");
+
+ EVP_PKEY_free(own_bi->pubkey);
+ own_bi->pubkey = NULL;
+
+ if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(own_bi) < 0)
+ goto fail;
+
+ return 0;
+fail:
+ dl_list_del(&own_bi->list);
+ dpp_bootstrap_info_free(own_bi);
+ return -1;
+}
+
+
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
+ dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
+ return -1;
+ return 0;
}
@@ -8631,14 +4171,15 @@ static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{
char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
+ char *key = NULL, *ppkey = NULL;
+ u8 *privkey = NULL, *pp_key = NULL;
+ size_t privkey_len = 0, pp_key_len = 0;
int ret = -1;
struct dpp_configurator *conf = NULL;
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+ ppkey = get_param(cmd, " ppkey=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -8648,7 +4189,16 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
goto fail;
}
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+ if (ppkey) {
+ pp_key_len = os_strlen(ppkey) / 2;
+ pp_key = os_malloc(pp_key_len);
+ if (!pp_key ||
+ hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
+ goto fail;
+ }
+
+ conf = dpp_keygen_configurator(curve, privkey, privkey_len,
+ pp_key, pp_key_len);
if (!conf)
goto fail;
@@ -8659,7 +4209,9 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
fail:
os_free(curve);
str_clear_free(key);
+ str_clear_free(ppkey);
bin_clear_free(privkey, privkey_len);
+ bin_clear_free(pp_key, pp_key_len);
dpp_configurator_free(conf);
return ret;
}
@@ -8719,62 +4271,76 @@ int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
#ifdef CONFIG_DPP2
-static void dpp_connection_free(struct dpp_connection *conn)
-{
- if (conn->sock >= 0) {
- wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
- conn->sock);
- eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
- eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
- close(conn->sock);
- }
- wpabuf_free(conn->msg);
- wpabuf_free(conn->msg_out);
- dpp_auth_deinit(conn->auth);
- os_free(conn);
-}
-
-
-static void dpp_connection_remove(struct dpp_connection *conn)
-{
- dl_list_del(&conn->list);
- dpp_connection_free(conn);
-}
-
-
-static void dpp_tcp_init_flush(struct dpp_global *dpp)
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key)
{
- struct dpp_connection *conn, *tmp;
-
- dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
- list)
- dpp_connection_remove(conn);
-}
+ struct dpp_configurator *conf;
+ const EC_KEY *eckey, *eckey_pp;
+ const EC_GROUP *group, *group_pp;
+ int nid;
+ const struct dpp_curve_params *curve;
+ if (!key->csign || !key->pp_key)
+ return -1;
+ eckey = EVP_PKEY_get0_EC_KEY(key->csign);
+ if (!eckey)
+ return -1;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ curve = dpp_get_curve_nid(nid);
+ if (!curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
+ return -1;
+ }
+ eckey_pp = EVP_PKEY_get0_EC_KEY(key->pp_key);
+ if (!eckey_pp)
+ return -1;
+ group_pp = EC_KEY_get0_group(eckey_pp);
+ if (!group_pp)
+ return -1;
+ if (EC_GROUP_get_curve_name(group) !=
+ EC_GROUP_get_curve_name(group_pp)) {
+ wpa_printf(MSG_INFO,
+ "DPP: Mismatch in c-sign-key and ppKey groups");
+ return -1;
+ }
-static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
-{
- struct dpp_connection *conn, *tmp;
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ return -1;
+ conf->curve = curve;
+ conf->csign = key->csign;
+ key->csign = NULL;
+ conf->pp_key = key->pp_key;
+ key->pp_key = NULL;
+ conf->own = 1;
+ if (dpp_configurator_gen_kid(conf) < 0) {
+ dpp_configurator_free(conf);
+ return -1;
+ }
- dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
- list)
- dpp_connection_remove(conn);
- os_free(ctrl);
+ conf->id = dpp_next_configurator_id(dpp);
+ dl_list_add(&dpp->configurator, &conf->list);
+ return conf->id;
}
-static void dpp_relay_flush_controllers(struct dpp_global *dpp)
+struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
+ const u8 *kid)
{
- struct dpp_relay_controller *ctrl, *tmp;
+ struct dpp_configurator *conf;
if (!dpp)
- return;
+ return NULL;
- dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
- struct dpp_relay_controller, list) {
- dl_list_del(&ctrl->list);
- dpp_relay_controller_free(ctrl);
+ dl_list_for_each(conf, &dpp->configurator,
+ struct dpp_configurator, list) {
+ if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
+ return conf;
}
+ return NULL;
}
#endif /* CONFIG_DPP2 */
@@ -8787,10 +4353,9 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config)
dpp = os_zalloc(sizeof(*dpp));
if (!dpp)
return NULL;
- dpp->msg_ctx = config->msg_ctx;
#ifdef CONFIG_DPP2
dpp->cb_ctx = config->cb_ctx;
- dpp->process_conf_obj = config->process_conf_obj;
+ dpp->remove_bi = config->remove_bi;
#endif /* CONFIG_DPP2 */
dl_list_init(&dpp->bootstrap);
@@ -8828,1229 +4393,33 @@ void dpp_global_deinit(struct dpp_global *dpp)
#ifdef CONFIG_DPP2
-static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
-static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
-static void dpp_controller_auth_success(struct dpp_connection *conn,
- int initiator);
-
-
-int dpp_relay_add_controller(struct dpp_global *dpp,
- struct dpp_relay_config *config)
-{
- struct dpp_relay_controller *ctrl;
-
- if (!dpp)
- return -1;
-
- ctrl = os_zalloc(sizeof(*ctrl));
- if (!ctrl)
- return -1;
- dl_list_init(&ctrl->conn);
- ctrl->global = dpp;
- os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
- os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
- ctrl->cb_ctx = config->cb_ctx;
- ctrl->tx = config->tx;
- ctrl->gas_resp_tx = config->gas_resp_tx;
- dl_list_add(&dpp->controllers, &ctrl->list);
- return 0;
-}
-
-
-static struct dpp_relay_controller *
-dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
-{
- struct dpp_relay_controller *ctrl;
-
- if (!dpp)
- return NULL;
-
- dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
- list) {
- if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
- return ctrl;
- }
-
- return NULL;
-}
-
-
-static void dpp_controller_gas_done(struct dpp_connection *conn)
-{
- struct dpp_authentication *auth = conn->auth;
-
- if (auth->peer_version >= 2 &&
- auth->conf_resp_status == DPP_STATUS_OK) {
- wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
- auth->waiting_conf_result = 1;
- return;
- }
-
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
- dpp_connection_remove(conn);
-}
-
-
-static int dpp_tcp_send(struct dpp_connection *conn)
-{
- int res;
-
- if (!conn->msg_out) {
- eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
- conn->write_eloop = 0;
- return -1;
- }
- res = send(conn->sock,
- wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
- wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
- strerror(errno));
- dpp_connection_remove(conn);
- return -1;
- }
-
- conn->msg_out_pos += res;
- if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
- wpa_printf(MSG_DEBUG,
- "DPP: %u/%u bytes of message sent to Controller",
- (unsigned int) conn->msg_out_pos,
- (unsigned int) wpabuf_len(conn->msg_out));
- if (!conn->write_eloop &&
- eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready, conn, NULL) == 0)
- conn->write_eloop = 1;
- return 1;
- }
-
- wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
- wpabuf_free(conn->msg_out);
- conn->msg_out = NULL;
- conn->msg_out_pos = 0;
- eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
- conn->write_eloop = 0;
- if (!conn->read_eloop &&
- eloop_register_sock(conn->sock, EVENT_TYPE_READ,
- dpp_controller_rx, conn, NULL) == 0)
- conn->read_eloop = 1;
- if (conn->on_tcp_tx_complete_remove) {
- dpp_connection_remove(conn);
- } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
- conn->auth) {
- dpp_controller_gas_done(conn);
- } else if (conn->on_tcp_tx_complete_auth_ok) {
- conn->on_tcp_tx_complete_auth_ok = 0;
- dpp_controller_auth_success(conn, 1);
- }
-
- return 0;
-}
-
-
-static void dpp_controller_start_gas_client(struct dpp_connection *conn)
-{
- struct dpp_authentication *auth = conn->auth;
- struct wpabuf *buf;
- char json[100];
- int netrole_ap = 0; /* TODO: make this configurable */
-
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
- if (!buf) {
- wpa_printf(MSG_DEBUG,
- "DPP: No configuration request data available");
- return;
- }
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
- if (!conn->msg_out) {
- wpabuf_free(buf);
- return;
- }
- wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
- wpabuf_len(buf) - 1);
- wpabuf_free(buf);
-
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return;
- conn->write_eloop = 1;
- }
- }
-}
-
-
-static void dpp_controller_auth_success(struct dpp_connection *conn,
- int initiator)
-{
- struct dpp_authentication *auth = conn->auth;
-
- if (!auth)
- return;
-
- wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(conn->global->msg_ctx, MSG_INFO,
- DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - stop at Authentication Confirm");
- if (auth->configurator) {
- /* Prevent GAS response */
- auth->auth_success = 0;
- }
- return;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (!auth->configurator)
- dpp_controller_start_gas_client(conn);
-}
-
-
-static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct dpp_connection *conn = eloop_ctx;
-
- wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
- dpp_tcp_send(conn);
-}
-
-
-static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
- const struct hostapd_ip_addr *ipaddr,
- int port)
-{
- struct sockaddr_in *dst;
-#ifdef CONFIG_IPV6
- struct sockaddr_in6 *dst6;
-#endif /* CONFIG_IPV6 */
-
- switch (ipaddr->af) {
- case AF_INET:
- dst = (struct sockaddr_in *) addr;
- os_memset(dst, 0, sizeof(*dst));
- dst->sin_family = AF_INET;
- dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
- dst->sin_port = htons(port);
- *addrlen = sizeof(*dst);
- break;
-#ifdef CONFIG_IPV6
- case AF_INET6:
- dst6 = (struct sockaddr_in6 *) addr;
- os_memset(dst6, 0, sizeof(*dst6));
- dst6->sin6_family = AF_INET6;
- os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
- sizeof(struct in6_addr));
- dst6->sin6_port = htons(port);
- *addrlen = sizeof(*dst6);
- break;
-#endif /* CONFIG_IPV6 */
- default:
- return -1;
- }
-
- return 0;
-}
-
-
-static struct dpp_connection *
-dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
- unsigned int freq)
-{
- struct dpp_connection *conn;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- char txt[100];
-
- if (dl_list_len(&ctrl->conn) >= 15) {
- wpa_printf(MSG_DEBUG,
- "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
- return NULL;
- }
-
- if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
- &ctrl->ipaddr, DPP_TCP_PORT) < 0)
- return NULL;
-
- conn = os_zalloc(sizeof(*conn));
- if (!conn)
- return NULL;
-
- conn->global = ctrl->global;
- conn->relay = ctrl;
- os_memcpy(conn->mac_addr, src, ETH_ALEN);
- conn->freq = freq;
-
- conn->sock = socket(AF_INET, SOCK_STREAM, 0);
- if (conn->sock < 0)
- goto fail;
- wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
- conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
-
- if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
- strerror(errno));
- goto fail;
- }
-
- if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
- if (errno != EINPROGRESS) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
- strerror(errno));
- goto fail;
- }
-
- /*
- * Continue connecting in the background; eloop will call us
- * once the connection is ready (or failed).
- */
- }
-
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready, conn, NULL) < 0)
- goto fail;
- conn->write_eloop = 1;
-
- /* TODO: eloop timeout to clear a connection if it does not complete
- * properly */
-
- dl_list_add(&ctrl->conn, &conn->list);
- return conn;
-fail:
- dpp_connection_free(conn);
- return NULL;
-}
-
-
-static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
{
struct wpabuf *msg;
- msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
- if (!msg)
- return NULL;
- wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
- wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
- wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
- wpabuf_put_data(msg, buf, len);
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
- return msg;
-}
-
-
-static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
- const u8 *buf, size_t len)
-{
- u8 type = hdr[DPP_HDR_LEN - 1];
-
- wpa_printf(MSG_DEBUG,
- "DPP: Continue already established Relay/Controller connection for this session");
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
- if (!conn->msg_out) {
- dpp_connection_remove(conn);
- return -1;
- }
-
- /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
- * TX status */
- if (type == DPP_PA_CONFIGURATION_RESULT)
- conn->on_tcp_tx_complete_remove = 1;
- dpp_tcp_send(conn);
- return 0;
-}
-
-
-int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
- const u8 *buf, size_t len, unsigned int freq,
- const u8 *i_bootstrap, const u8 *r_bootstrap)
-{
- struct dpp_relay_controller *ctrl;
- struct dpp_connection *conn;
- u8 type = hdr[DPP_HDR_LEN - 1];
-
- /* Check if there is an already started session for this peer and if so,
- * continue that session (send this over TCP) and return 0.
- */
- if (type != DPP_PA_PEER_DISCOVERY_REQ &&
- type != DPP_PA_PEER_DISCOVERY_RESP) {
- dl_list_for_each(ctrl, &dpp->controllers,
- struct dpp_relay_controller, list) {
- dl_list_for_each(conn, &ctrl->conn,
- struct dpp_connection, list) {
- if (os_memcmp(src, conn->mac_addr,
- ETH_ALEN) == 0)
- return dpp_relay_tx(conn, hdr, buf, len);
- }
- }
- }
-
- if (!r_bootstrap)
- return -1;
-
- ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
- if (!ctrl)
- return -1;
-
- wpa_printf(MSG_DEBUG,
- "DPP: Authentication Request for a configured Controller");
- conn = dpp_relay_new_conn(ctrl, src, freq);
- if (!conn)
- return -1;
-
- conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
- if (!conn->msg_out) {
- dpp_connection_remove(conn);
- return -1;
- }
- /* Message will be sent in dpp_conn_tx_ready() */
-
- return 0;
-}
-
-
-int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
- size_t data_len)
-{
- struct dpp_relay_controller *ctrl;
- struct dpp_connection *conn, *found = NULL;
- struct wpabuf *msg;
-
- /* Check if there is a successfully completed authentication for this
- * and if so, continue that session (send this over TCP) and return 0.
- */
- dl_list_for_each(ctrl, &dpp->controllers,
- struct dpp_relay_controller, list) {
- if (found)
- break;
- dl_list_for_each(conn, &ctrl->conn,
- struct dpp_connection, list) {
- if (os_memcmp(src, conn->mac_addr,
- ETH_ALEN) == 0) {
- found = conn;
- break;
- }
- }
- }
-
- if (!found)
- return -1;
-
- msg = wpabuf_alloc(4 + 1 + data_len);
- if (!msg)
- return -1;
- wpabuf_put_be32(msg, 1 + data_len);
- wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
- wpabuf_put_data(msg, data, data_len);
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = msg;
- dpp_tcp_send(conn);
- return 0;
-}
-
-
-static void dpp_controller_free(struct dpp_controller *ctrl)
-{
- struct dpp_connection *conn, *tmp;
-
- if (!ctrl)
- return;
-
- dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
- list)
- dpp_connection_remove(conn);
-
- if (ctrl->sock >= 0) {
- close(ctrl->sock);
- eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
- }
- os_free(ctrl->configurator_params);
- os_free(ctrl);
-}
-
-
-static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
- const u8 *hdr, const u8 *buf, size_t len)
-{
- const u8 *r_bootstrap, *i_bootstrap;
- u16 r_bootstrap_len, i_bootstrap_len;
- struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
-
- if (!conn->ctrl)
- return 0;
-
- wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
-
- r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
- &r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_INFO,
- "Missing or invalid required Responder Bootstrapping Key Hash attribute");
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
- r_bootstrap, r_bootstrap_len);
-
- i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
- &i_bootstrap_len);
- if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_INFO,
- "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
- i_bootstrap, i_bootstrap_len);
-
- /* Try to find own and peer bootstrapping key matches based on the
- * received hash values */
- dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
- &own_bi, &peer_bi);
- if (!own_bi) {
- wpa_printf(MSG_INFO,
- "No matching own bootstrapping key found - ignore message");
- return -1;
- }
-
- if (conn->auth) {
- wpa_printf(MSG_INFO,
- "Already in DPP authentication exchange - ignore new one");
- return 0;
- }
-
- conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
- conn->ctrl->allowed_roles,
- conn->ctrl->qr_mutual,
- peer_bi, own_bi, -1, hdr, buf, len);
- if (!conn->auth) {
- wpa_printf(MSG_DEBUG, "DPP: No response generated");
- return -1;
- }
-
- if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
- conn->auth,
- conn->ctrl->configurator_params) < 0) {
- dpp_connection_remove(conn);
- return -1;
- }
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
- if (!conn->msg_out)
- return -1;
- wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
- wpabuf_len(conn->auth->resp_msg) - 1);
-
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return -1;
- conn->write_eloop = 1;
- }
- }
-
- return 0;
-}
-
-
-static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
- const u8 *hdr, const u8 *buf, size_t len)
-{
- struct dpp_authentication *auth = conn->auth;
- struct wpabuf *msg;
-
- if (!auth)
- return -1;
-
- wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
-
- msg = dpp_auth_resp_rx(auth, hdr, buf, len);
- if (!msg) {
- if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
- wpa_printf(MSG_DEBUG,
- "DPP: Start wait for full response");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
- dpp_connection_remove(conn);
- return -1;
- }
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
- if (!conn->msg_out) {
- wpabuf_free(msg);
- return -1;
- }
- wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
- wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
- wpabuf_len(msg) - 1);
- wpabuf_free(msg);
-
- conn->on_tcp_tx_complete_auth_ok = 1;
- if (dpp_tcp_send(conn) == 1) {
- if (!conn->write_eloop) {
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready,
- conn, NULL) < 0)
- return -1;
- conn->write_eloop = 1;
- }
- }
-
- return 0;
-}
-
-
-static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
- const u8 *hdr, const u8 *buf, size_t len)
-{
- struct dpp_authentication *auth = conn->auth;
-
- wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
-
- if (!auth) {
- wpa_printf(MSG_DEBUG,
- "DPP: No DPP Authentication in progress - drop");
- return -1;
- }
-
- if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
- return -1;
- }
-
- dpp_controller_auth_success(conn, 0);
- return 0;
-}
-
-
-static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
- const u8 *hdr, const u8 *buf,
- size_t len)
-{
- struct dpp_authentication *auth = conn->auth;
- enum dpp_status_error status;
-
- if (!conn->ctrl)
- return 0;
-
- wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
-
- if (!auth || !auth->waiting_conf_result) {
- wpa_printf(MSG_DEBUG,
- "DPP: No DPP Configuration waiting for result - drop");
- return -1;
- }
-
- status = dpp_conf_result_rx(auth, hdr, buf, len);
- if (status == DPP_STATUS_OK)
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
- DPP_EVENT_CONF_SENT);
- else
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
- DPP_EVENT_CONF_FAILED);
- return -1; /* to remove the completed connection */
-}
-
-
-static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
- size_t len)
-{
- const u8 *pos, *end;
- u8 type;
-
- wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
- pos = msg;
- end = msg + len;
-
- if (end - pos < DPP_HDR_LEN ||
- WPA_GET_BE24(pos) != OUI_WFA ||
- pos[3] != DPP_OUI_TYPE) {
- wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
- return -1;
- }
-
- if (pos[4] != 1) {
- wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
- pos[4]);
- return -1;
- }
- type = pos[5];
- wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
- pos += DPP_HDR_LEN;
-
- wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
- pos, end - pos);
- if (dpp_check_attrs(pos, end - pos) < 0)
- return -1;
-
- if (conn->relay) {
- wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
- conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
- conn->freq, msg, len);
- return 0;
- }
-
- switch (type) {
- case DPP_PA_AUTHENTICATION_REQ:
- return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
- case DPP_PA_AUTHENTICATION_RESP:
- return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
- case DPP_PA_AUTHENTICATION_CONF:
- return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
- case DPP_PA_CONFIGURATION_RESULT:
- return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
- default:
- /* TODO: missing messages types */
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported frame subtype %d", type);
- return -1;
- }
-}
-
-
-static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
- size_t len)
-{
- const u8 *pos, *end, *next;
- u8 dialog_token;
- const u8 *adv_proto;
- u16 slen;
- struct wpabuf *resp, *buf;
- struct dpp_authentication *auth = conn->auth;
-
- if (len < 1 + 2)
- return -1;
-
- wpa_printf(MSG_DEBUG,
- "DPP: Received DPP Configuration Request over TCP");
-
- if (!conn->ctrl || !auth || !auth->auth_success) {
- wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
- return -1;
- }
-
- pos = msg;
- end = msg + len;
-
- dialog_token = *pos++;
- adv_proto = pos++;
- slen = *pos++;
- if (*adv_proto != WLAN_EID_ADV_PROTO ||
- slen > end - pos || slen < 2)
- return -1;
-
- next = pos + slen;
- pos++; /* skip QueryRespLenLimit and PAME-BI */
-
- if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
- pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
- pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
- return -1;
-
- pos = next;
- /* Query Request */
- if (end - pos < 2)
- return -1;
- slen = WPA_GET_LE16(pos);
- pos += 2;
- if (slen > end - pos)
- return -1;
-
- resp = dpp_conf_req_rx(auth, pos, slen);
- if (!resp)
- return -1;
-
- buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
- if (!buf) {
- wpabuf_free(resp);
- return -1;
- }
-
- wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
-
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
-
- dpp_write_adv_proto(buf);
- dpp_write_gas_query(buf, resp);
- wpabuf_free(resp);
-
- /* Send Config Response over TCP; GAS fragmentation is taken care of by
- * the Relay */
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = buf;
- conn->on_tcp_tx_complete_gas_done = 1;
- dpp_tcp_send(conn);
- return 0;
-}
-
-
-static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
-{
- struct dpp_authentication *auth = conn->auth;
- int res;
- struct wpabuf *msg, *encaps;
- enum dpp_status_error status;
-
- wpa_printf(MSG_DEBUG,
- "DPP: Configuration Response for local stack from TCP");
-
- res = dpp_conf_resp_rx(auth, resp);
- wpabuf_free(resp);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
- return -1;
- }
-
- if (conn->global->process_conf_obj)
- res = conn->global->process_conf_obj(conn->global->cb_ctx,
- auth);
- else
- res = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
- if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
- return -1;
-
- wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
- status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
- msg = dpp_build_conf_result(auth, status);
+ msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
if (!msg)
- return -1;
-
- encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
- if (!encaps) {
- wpabuf_free(msg);
- return -1;
- }
- wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
- wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
- wpabuf_free(msg);
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
-
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = encaps;
- conn->on_tcp_tx_complete_remove = 1;
- dpp_tcp_send(conn);
-
- /* This exchange will be terminated in the TX status handler */
-
- return 0;
-}
-
-
-static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
- size_t len)
-{
- struct wpabuf *buf;
- u8 dialog_token;
- const u8 *pos, *end, *next, *adv_proto;
- u16 status, slen;
-
- if (len < 5 + 2)
- return -1;
-
- wpa_printf(MSG_DEBUG,
- "DPP: Received DPP Configuration Response over TCP");
-
- pos = msg;
- end = msg + len;
-
- dialog_token = *pos++;
- status = WPA_GET_LE16(pos);
- if (status != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
- return -1;
- }
- pos += 2;
- pos += 2; /* ignore GAS Comeback Delay */
-
- adv_proto = pos++;
- slen = *pos++;
- if (*adv_proto != WLAN_EID_ADV_PROTO ||
- slen > end - pos || slen < 2)
- return -1;
-
- next = pos + slen;
- pos++; /* skip QueryRespLenLimit and PAME-BI */
-
- if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
- pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
- pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
- return -1;
-
- pos = next;
- /* Query Response */
- if (end - pos < 2)
- return -1;
- slen = WPA_GET_LE16(pos);
- pos += 2;
- if (slen > end - pos)
- return -1;
-
- buf = wpabuf_alloc(slen);
- if (!buf)
- return -1;
- wpabuf_put_data(buf, pos, slen);
-
- if (!conn->relay && !conn->ctrl)
- return dpp_tcp_rx_gas_resp(conn, buf);
-
- if (!conn->relay) {
- wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
- wpabuf_free(buf);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
- conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
- dialog_token, 0, buf);
-
- return 0;
-}
-
-
-static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
-{
- struct dpp_connection *conn = eloop_ctx;
- int res;
- const u8 *pos;
-
- wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
- sd);
-
- if (conn->msg_len_octets < 4) {
- u32 msglen;
-
- res = recv(sd, &conn->msg_len[conn->msg_len_octets],
- 4 - conn->msg_len_octets, 0);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
- strerror(errno));
- dpp_connection_remove(conn);
- return;
- }
- if (res == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: No more data available over TCP");
- dpp_connection_remove(conn);
- return;
- }
- wpa_printf(MSG_DEBUG,
- "DPP: Received %d/%d octet(s) of message length field",
- res, (int) (4 - conn->msg_len_octets));
- conn->msg_len_octets += res;
-
- if (conn->msg_len_octets < 4) {
- wpa_printf(MSG_DEBUG,
- "DPP: Need %d more octets of message length field",
- (int) (4 - conn->msg_len_octets));
- return;
- }
-
- msglen = WPA_GET_BE32(conn->msg_len);
- wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
- if (msglen > 65535) {
- wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
- dpp_connection_remove(conn);
- return;
- }
-
- wpabuf_free(conn->msg);
- conn->msg = wpabuf_alloc(msglen);
- }
-
- if (!conn->msg) {
- wpa_printf(MSG_DEBUG,
- "DPP: No buffer available for receiving the message");
- dpp_connection_remove(conn);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
- (unsigned int) wpabuf_tailroom(conn->msg));
-
- res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
- dpp_connection_remove(conn);
- return;
- }
- if (res == 0) {
- wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
- dpp_connection_remove(conn);
- return;
- }
- wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
- wpabuf_put(conn->msg, res);
-
- if (wpabuf_tailroom(conn->msg) > 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Need %u more octets of message payload",
- (unsigned int) wpabuf_tailroom(conn->msg));
- return;
- }
-
- conn->msg_len_octets = 0;
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
- if (wpabuf_len(conn->msg) < 1) {
- dpp_connection_remove(conn);
- return;
- }
-
- pos = wpabuf_head(conn->msg);
- switch (*pos) {
- case WLAN_PA_VENDOR_SPECIFIC:
- if (dpp_controller_rx_action(conn, pos + 1,
- wpabuf_len(conn->msg) - 1) < 0)
- dpp_connection_remove(conn);
- break;
- case WLAN_PA_GAS_INITIAL_REQ:
- if (dpp_controller_rx_gas_req(conn, pos + 1,
- wpabuf_len(conn->msg) - 1) < 0)
- dpp_connection_remove(conn);
- break;
- case WLAN_PA_GAS_INITIAL_RESP:
- if (dpp_rx_gas_resp(conn, pos + 1,
- wpabuf_len(conn->msg) - 1) < 0)
- dpp_connection_remove(conn);
- break;
- default:
- wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
- *pos);
- break;
- }
-}
-
-
-static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
-{
- struct dpp_controller *ctrl = eloop_ctx;
- struct sockaddr_in addr;
- socklen_t addr_len = sizeof(addr);
- int fd;
- struct dpp_connection *conn;
-
- wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
-
- fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
- if (fd < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to accept new connection: %s",
- strerror(errno));
- return;
- }
- wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-
- conn = os_zalloc(sizeof(*conn));
- if (!conn)
- goto fail;
-
- conn->global = ctrl->global;
- conn->ctrl = ctrl;
- conn->sock = fd;
-
- if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
- strerror(errno));
- goto fail;
- }
-
- if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
- dpp_controller_rx, conn, NULL) < 0)
- goto fail;
- conn->read_eloop = 1;
-
- /* TODO: eloop timeout to expire connections that do not complete in
- * reasonable time */
- dl_list_add(&ctrl->conn, &conn->list);
- return;
-
-fail:
- close(fd);
- os_free(conn);
-}
-
-
-int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port)
-{
- struct dpp_connection *conn;
- struct sockaddr_storage saddr;
- socklen_t addrlen;
- const u8 *hdr, *pos, *end;
- char txt[100];
-
- wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
- hostapd_ip_txt(addr, txt, sizeof(txt)), port);
- if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
- addr, port) < 0) {
- dpp_auth_deinit(auth);
- return -1;
- }
-
- conn = os_zalloc(sizeof(*conn));
- if (!conn) {
- dpp_auth_deinit(auth);
- return -1;
- }
-
- conn->global = dpp;
- conn->auth = auth;
- conn->sock = socket(AF_INET, SOCK_STREAM, 0);
- if (conn->sock < 0)
- goto fail;
-
- if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
- strerror(errno));
- goto fail;
- }
-
- if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
- if (errno != EINPROGRESS) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
- strerror(errno));
- goto fail;
- }
-
- /*
- * Continue connecting in the background; eloop will call us
- * once the connection is ready (or failed).
- */
- }
-
- if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
- dpp_conn_tx_ready, conn, NULL) < 0)
- goto fail;
- conn->write_eloop = 1;
-
- hdr = wpabuf_head(auth->req_msg);
- end = hdr + wpabuf_len(auth->req_msg);
- hdr += 2; /* skip Category and Actiom */
- pos = hdr + DPP_HDR_LEN;
- conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
- if (!conn->msg_out)
- goto fail;
- /* Message will be sent in dpp_conn_tx_ready() */
+ return NULL;
- /* TODO: eloop timeout to clear a connection if it does not complete
- * properly */
- dl_list_add(&dpp->tcp_init, &conn->list);
- return 0;
-fail:
- dpp_connection_free(conn);
- return -1;
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Presence Announcement frame attributes", msg);
+ return msg;
}
-int dpp_controller_start(struct dpp_global *dpp,
- struct dpp_controller_config *config)
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash)
{
- struct dpp_controller *ctrl;
- int on = 1;
- struct sockaddr_in sin;
- int port;
-
- if (!dpp || dpp->controller)
- return -1;
-
- ctrl = os_zalloc(sizeof(*ctrl));
- if (!ctrl)
- return -1;
- ctrl->global = dpp;
- if (config->configurator_params)
- ctrl->configurator_params =
- os_strdup(config->configurator_params);
- dl_list_init(&ctrl->conn);
- /* TODO: configure these somehow */
- ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
- ctrl->qr_mutual = 0;
-
- ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
- if (ctrl->sock < 0)
- goto fail;
-
- if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
- &on, sizeof(on)) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: setsockopt(SO_REUSEADDR) failed: %s",
- strerror(errno));
- /* try to continue anyway */
- }
-
- if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
- wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
- strerror(errno));
- goto fail;
- }
+ char hex[SHA256_MAC_LEN * 2 + 1];
- /* TODO: IPv6 */
- os_memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
- sin.sin_port = htons(port);
- if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- wpa_printf(MSG_INFO,
- "DPP: Failed to bind Controller TCP port: %s",
- strerror(errno));
- goto fail;
- }
- if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
- fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
- eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
- dpp_controller_tcp_cb, ctrl, NULL))
- goto fail;
-
- dpp->controller = ctrl;
- wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
- return 0;
-fail:
- dpp_controller_free(ctrl);
- return -1;
-}
-
-
-void dpp_controller_stop(struct dpp_global *dpp)
-{
- if (dpp) {
- dpp_controller_free(dpp->controller);
- dpp->controller = NULL;
- }
+ wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
+ wpa_msg(msg_ctx, MSG_INFO,
+ DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
+ id, MAC2STR(src), freq, hex);
}
#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/common/dpp.h b/contrib/wpa/src/common/dpp.h
index db640efe86b9..75de3cae93e9 100644
--- a/contrib/wpa/src/common/dpp.h
+++ b/contrib/wpa/src/common/dpp.h
@@ -1,7 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,9 +20,22 @@
struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
+struct json_token;
+struct dpp_reconfig_id;
+
+#ifdef CONFIG_TESTING_OPTIONS
+#define DPP_VERSION (dpp_version_override)
+extern int dpp_version_override;
+#else /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+#define DPP_VERSION 2
+#else
+#define DPP_VERSION 1
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
-#define DPP_TCP_PORT 7871
+#define DPP_TCP_PORT 8908
enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0,
@@ -35,6 +48,12 @@ enum dpp_public_action_frame_type {
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
+ DPP_PA_CONNECTION_STATUS_RESULT = 12,
+ DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
+ DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
+ DPP_PA_RECONFIG_AUTH_REQ = 15,
+ DPP_PA_RECONFIG_AUTH_RESP = 16,
+ DPP_PA_RECONFIG_AUTH_CONF = 17,
};
enum dpp_attribute_id {
@@ -64,6 +83,14 @@ enum dpp_attribute_id {
DPP_ATTR_CHANNEL = 0x1018,
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
DPP_ATTR_ENVELOPED_DATA = 0x101A,
+ DPP_ATTR_SEND_CONN_STATUS = 0x101B,
+ DPP_ATTR_CONN_STATUS = 0x101C,
+ DPP_ATTR_RECONFIG_FLAGS = 0x101D,
+ DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
+ DPP_ATTR_CSR_ATTR_REQ = 0x101F,
+ DPP_ATTR_A_NONCE = 0x1020,
+ DPP_ATTR_E_PRIME_ID = 0x1021,
+ DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
};
enum dpp_status_error {
@@ -77,6 +104,16 @@ enum dpp_status_error {
DPP_STATUS_INVALID_CONNECTOR = 7,
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
+ DPP_STATUS_NO_AP = 10,
+ DPP_STATUS_CONFIGURE_PENDING = 11,
+ DPP_STATUS_CSR_NEEDED = 12,
+ DPP_STATUS_CSR_BAD = 13,
+};
+
+/* DPP Reconfig Flags object - connectorKey values */
+enum dpp_connector_key {
+ DPP_CONFIG_REUSEKEY = 0,
+ DPP_CONFIG_REPLACEKEY = 1,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -87,6 +124,7 @@ enum dpp_status_error {
#define DPP_MAX_NONCE_LEN 32
#define DPP_MAX_HASH_LEN 64
#define DPP_MAX_SHARED_SECRET_LEN 66
+#define DPP_CP_LEN 64
struct dpp_curve_params {
const char *name;
@@ -102,6 +140,7 @@ struct dpp_curve_params {
enum dpp_bootstrap_type {
DPP_BOOTSTRAP_QR_CODE,
DPP_BOOTSTRAP_PKEX,
+ DPP_BOOTSTRAP_NFC_URI,
};
struct dpp_bootstrap_info {
@@ -110,15 +149,23 @@ struct dpp_bootstrap_info {
enum dpp_bootstrap_type type;
char *uri;
u8 mac_addr[ETH_ALEN];
+ char *chan;
char *info;
+ char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
+ bool channels_listed;
+ u8 version;
int own;
EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
+ u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
unsigned int pkex_t; /* number of failures before dpp_pkex
* instantiation */
+ int nfc_negotiated; /* whether this has been used in NFC negotiated
+ * connection handover */
+ char *configurator_params;
};
#define PKEX_COUNTER_T_LIMIT 5
@@ -155,12 +202,21 @@ enum dpp_akm {
DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP,
+ DPP_AKM_DOT1X,
+};
+
+enum dpp_netrole {
+ DPP_NETROLE_STA,
+ DPP_NETROLE_AP,
+ DPP_NETROLE_CONFIGURATOR,
};
struct dpp_configuration {
u8 ssid[32];
size_t ssid_len;
+ int ssid_charset;
enum dpp_akm akm;
+ enum dpp_netrole netrole;
/* For DPP configuration (connector) */
os_time_t netaccesskey_expiry;
@@ -172,29 +228,51 @@ struct dpp_configuration {
char *passphrase;
u8 psk[32];
int psk_set;
+
+ char *csrattrs;
};
+struct dpp_asymmetric_key {
+ struct dpp_asymmetric_key *next;
+ EVP_PKEY *csign;
+ EVP_PKEY *pp_key;
+ char *config_template;
+ char *connector_template;
+};
+
+#define DPP_MAX_CONF_OBJ 10
+
struct dpp_authentication {
+ struct dpp_global *global;
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
+ struct dpp_bootstrap_info *tmp_peer_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending;
+ int reconfig;
+ enum dpp_connector_key reconfig_connector_key;
enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status;
+ enum dpp_status_error force_conf_resp_status;
u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN];
u8 e_nonce[DPP_MAX_NONCE_LEN];
+ u8 c_nonce[DPP_MAX_NONCE_LEN];
u8 i_capab;
u8 r_capab;
+ enum dpp_netrole e_netrole;
EVP_PKEY *own_protocol_key;
EVP_PKEY *peer_protocol_key;
+ EVP_PKEY *reconfig_old_protocol_key;
struct wpabuf *req_msg;
struct wpabuf *resp_msg;
+ struct wpabuf *reconfig_req_msg;
+ struct wpabuf *reconfig_resp_msg;
/* Intersection of possible frequencies for initiating DPP
* Authentication exchange */
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
@@ -212,6 +290,7 @@ struct dpp_authentication {
u8 k1[DPP_MAX_HASH_LEN];
u8 k2[DPP_MAX_HASH_LEN];
u8 ke[DPP_MAX_HASH_LEN];
+ u8 bk[DPP_MAX_HASH_LEN];
int initiator;
int waiting_auth_resp;
int waiting_auth_conf;
@@ -222,22 +301,54 @@ struct dpp_authentication {
int remove_on_tx_status;
int connect_on_tx_status;
int waiting_conf_result;
+ int waiting_conn_status_result;
int auth_success;
+ bool reconfig_success;
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
+ struct wpabuf *conf_resp_tcp;
struct dpp_configuration *conf_ap;
+ struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
+ struct dpp_configuration *conf2_sta;
+ int provision_configurator;
struct dpp_configurator *conf;
- char *connector; /* received signedConnector */
- u8 ssid[SSID_MAX_LEN];
- u8 ssid_len;
- char passphrase[64];
- u8 psk[PMK_LEN];
- int psk_set;
- enum dpp_akm akm;
+ struct dpp_config_obj {
+ char *connector; /* received signedConnector */
+ u8 ssid[SSID_MAX_LEN];
+ u8 ssid_len;
+ int ssid_charset;
+ char passphrase[64];
+ u8 psk[PMK_LEN];
+ int psk_set;
+ enum dpp_akm akm;
+ struct wpabuf *c_sign_key;
+ struct wpabuf *certbag;
+ struct wpabuf *certs;
+ struct wpabuf *cacert;
+ char *server_name;
+ struct wpabuf *pp_key;
+ } conf_obj[DPP_MAX_CONF_OBJ];
+ unsigned int num_conf_obj;
+ struct dpp_asymmetric_key *conf_key_pkg;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
- struct wpabuf *c_sign_key;
+ int send_conn_status;
+ int conn_status_requested;
+ int akm_use_selector;
+ int configurator_set;
+ u8 transaction_id;
+ u8 *csrattrs;
+ size_t csrattrs_len;
+ bool waiting_csr;
+ struct wpabuf *csr;
+ struct wpabuf *priv_key; /* DER-encoded private key used for csr */
+ bool waiting_cert;
+ char *trusted_eap_server_name;
+ struct wpabuf *cacert;
+ struct wpabuf *certbag;
+ void *cert_resp_ctx;
+ void *gas_server_ctx;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -251,8 +362,12 @@ struct dpp_configurator {
unsigned int id;
int own;
EVP_PKEY *csign;
+ u8 kid_hash[SHA256_MAC_LEN];
char *kid;
const struct dpp_curve_params *curve;
+ char *connector; /* own Connector for reconfiguration */
+ EVP_PKEY *connector_key;
+ EVP_PKEY *pp_key;
};
struct dpp_introduction {
@@ -265,6 +380,7 @@ struct dpp_relay_config {
const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash;
+ void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@@ -275,6 +391,12 @@ struct dpp_relay_config {
struct dpp_controller_config {
const char *configurator_params;
int tcp_port;
+ u8 allowed_roles;
+ int qr_mutual;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
#ifdef CONFIG_TESTING_OPTIONS
@@ -386,16 +508,16 @@ extern size_t dpp_nonce_override_len;
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list);
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
-struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri);
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len);
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi);
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
struct hostapd_hw_modes;
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@@ -403,8 +525,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct hostapd_hw_modes *own_modes,
u16 num_modes);
struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
- struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+ int qr_mutual, struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len);
@@ -413,6 +535,10 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
const char *json);
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name,
+ enum dpp_netrole netrole,
+ const char *mud_url, int *opclasses);
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
@@ -425,11 +551,13 @@ int dpp_akm_dpp(enum dpp_akm akm);
int dpp_akm_ver2(enum dpp_akm akm);
int dpp_configuration_valid(const struct dpp_configuration *conf);
void dpp_configuration_free(struct dpp_configuration *conf);
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_authentication *auth,
- const char *cmd);
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf *
+dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
+ u16 e_nonce_len, enum dpp_netrole netrole,
+ bool cert_req);
+struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth,
@@ -439,18 +567,26 @@ enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status);
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len);
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
int dpp_check_attrs(const u8 *buf, size_t len);
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
const char * dpp_akm_str(enum dpp_akm akm);
+const char * dpp_akm_selector_str(enum dpp_akm akm);
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
-struct dpp_configurator *
-dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len);
int dpp_configurator_own_config(struct dpp_authentication *auth,
const char *curve, int ap);
enum dpp_status_error
@@ -495,8 +631,15 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
+ const char *name);
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
+
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri);
+struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
+ const char *uri);
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd);
struct dpp_bootstrap_info *
dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id);
@@ -507,36 +650,87 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
char *reply, int reply_size);
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
const u8 *r_bootstrap,
struct dpp_bootstrap_info **own_bi,
struct dpp_bootstrap_info **peer_bi);
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash);
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key);
+struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
+ const u8 *kid);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
const u8 *buf, size_t len, unsigned int freq,
- const u8 *i_bootstrap, const u8 *r_bootstrap);
+ const u8 *i_bootstrap, const u8 *r_bootstrap,
+ void *cb_ctx);
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
size_t data_len);
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id);
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port);
+ const struct hostapd_ip_addr *addr, int port,
+ const char *name, enum dpp_netrole netrole, void *msg_ctx,
+ void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth));
+
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash);
struct dpp_global_config {
- void *msg_ctx;
void *cb_ctx;
- int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
};
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
void dpp_global_clear(struct dpp_global *dpp);
void dpp_global_deinit(struct dpp_global *dpp);
+/* dpp_reconfig.c */
+
+struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id);
+struct dpp_authentication *
+dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len);
+struct dpp_authentication *
+dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
+ const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ unsigned int freq, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+struct wpabuf *
+dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *pp_key,
+ size_t pp_key_len);
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
+
#endif /* CONFIG_DPP */
#endif /* DPP_H */
diff --git a/contrib/wpa/src/common/dpp_auth.c b/contrib/wpa/src/common/dpp_auth.c
new file mode 100644
index 000000000000..0cabd647fb81
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_auth.c
@@ -0,0 +1,1977 @@
+/*
+ * DPP authentication exchange
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "crypto/random.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+u8 dpp_protocol_key_override[600];
+size_t dpp_protocol_key_override_len = 0;
+u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+size_t dpp_nonce_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
+ const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+static void dpp_auth_success(struct dpp_authentication *auth)
+{
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication success - clear temporary keys");
+ os_memset(auth->Mx, 0, sizeof(auth->Mx));
+ auth->Mx_len = 0;
+ os_memset(auth->Nx, 0, sizeof(auth->Nx));
+ auth->Nx_len = 0;
+ os_memset(auth->Lx, 0, sizeof(auth->Lx));
+ auth->Lx_len = 0;
+ os_memset(auth->k1, 0, sizeof(auth->k1));
+ os_memset(auth->k2, 0, sizeof(auth->k2));
+
+ auth->auth_success = 1;
+}
+
+
+static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
+ const struct wpabuf *pi,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ unsigned int neg_freq)
+{
+ struct wpabuf *msg;
+ u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
+ u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
+ u8 *pos;
+ const u8 *addr[2];
+ size_t len[2], siv_len, attr_len;
+ u8 *attr_start, *attr_end;
+
+ /* Build DPP Authentication Request frame attributes */
+ attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
+ 4 + sizeof(wrapped_data);
+ if (neg_freq > 0)
+ attr_len += 4 + 2;
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Initiator Protocol Key */
+ if (pi) {
+ wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pi));
+ wpabuf_put_buf(msg, pi);
+ }
+
+ /* Channel */
+ if (neg_freq > 0) {
+ u8 op_class, channel;
+
+ if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
+ &channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported negotiation frequency request: %d",
+ neg_freq);
+ wpabuf_free(msg);
+ return NULL;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_u8(msg, op_class);
+ wpabuf_put_u8(msg, channel);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ if (DPP_VERSION > 1) {
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({I-nonce, I-capabilities}k1) */
+ pos = clear;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ goto skip_i_nonce;
+ }
+ if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len - 1);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len - 1);
+ pos += nonce_len - 1;
+ goto skip_i_nonce;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len);
+ pos += nonce_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_nonce:
+ if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
+ goto skip_i_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->i_capab = auth->allowed_roles;
+ *pos++ = auth->i_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
+ pos[-1] = 0;
+ }
+skip_i_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Request frame attributes", msg);
+
+ return msg;
+}
+
+
+static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
+ enum dpp_status_error status,
+ const struct wpabuf *pr,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ const u8 *r_nonce, const u8 *i_nonce,
+ const u8 *wrapped_r_auth,
+ size_t wrapped_r_auth_len,
+ const u8 *siv_key)
+{
+ struct wpabuf *msg;
+#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
+ 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
+ u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
+ u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
+ const u8 *addr[2];
+ size_t len[2], siv_len, attr_len;
+ u8 *attr_start, *attr_end, *pos;
+
+ auth->waiting_auth_conf = 1;
+ auth->auth_resp_status = status;
+ auth->auth_resp_tries = 0;
+
+ /* Build DPP Authentication Response frame attributes */
+ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+ 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ if (status != 255)
+ dpp_build_attr_status(msg, status);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Responder Protocol Key */
+ if (pr) {
+ wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pr));
+ wpabuf_put_buf(msg, pr);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ if (auth->peer_version >= 2) {
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
+ attr_end = wpabuf_put(msg, 0);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
+ pos = clear;
+
+ if (r_nonce) {
+ /* R-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, r_nonce, nonce_len);
+ pos += nonce_len;
+ }
+
+ if (i_nonce) {
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, i_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
+ pos[nonce_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ pos += nonce_len;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
+ goto skip_r_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* R-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
+ DPP_CAPAB_ENROLLEE;
+ *pos++ = auth->r_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
+ pos[-1] = 0;
+ } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - incompatible R-capabilities");
+ if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
+ pos[-1] = 0;
+ else
+ pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
+ DPP_CAPAB_CONFIGURATOR;
+ }
+skip_r_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wrapped_r_auth) {
+ /* {R-auth}ke */
+ WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
+ pos += 2;
+ WPA_PUT_LE16(pos, wrapped_r_auth_len);
+ pos += 2;
+ os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
+ pos += wrapped_r_auth_len;
+ }
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Response frame attributes", msg);
+ return msg;
+}
+
+
+static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
+{
+ size_t nonce_len;
+ size_t secret_len;
+ struct wpabuf *msg, *pr = NULL;
+ u8 r_auth[4 + DPP_MAX_HASH_LEN];
+ u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
+ size_t wrapped_r_auth_len;
+ int ret = -1;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
+ enum dpp_status_error status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+ if (!auth->own_bi)
+ return -1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->r_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate R-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->r_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
+
+ EVP_PKEY_free(auth->own_protocol_key);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!auth->own_protocol_key)
+ goto fail;
+
+ pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pr)
+ goto fail;
+
+ /* ECDH: N = pR * PI */
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ auth->Nx, &secret_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
+ auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
+
+ if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ if (auth->own_bi && auth->peer_bi) {
+ /* Mutual authentication */
+ if (dpp_auth_derive_l_responder(auth) < 0)
+ goto fail;
+ }
+
+ if (dpp_derive_bk_ke(auth) < 0)
+ goto fail;
+
+ /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
+ WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
+ if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
+ goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
+ r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ r_auth, 4 + auth->curve->hash_len,
+ 0, NULL, NULL, wrapped_r_auth) < 0)
+ goto fail;
+ wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
+ wrapped_r_auth, wrapped_r_auth_len);
+ w_r_auth = wrapped_r_auth;
+
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+ r_nonce = auth->r_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
+ wpabuf_free(pr);
+ pr = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
+ wpabuf_free(pr);
+ pr = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
+ goto fail;
+ } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
+ w_r_auth = NULL;
+ wrapped_r_auth_len = 0;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
+ r_nonce = NULL;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ r_nonce, i_nonce,
+ w_r_auth, wrapped_r_auth_len,
+ auth->k2);
+ if (!msg)
+ goto fail;
+ wpabuf_free(auth->resp_msg);
+ auth->resp_msg = msg;
+ ret = 0;
+fail:
+ wpabuf_free(pr);
+ return ret;
+}
+
+
+static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->own_bi)
+ return -1;
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ NULL, i_nonce, NULL, 0, auth->k1);
+ if (!msg)
+ return -1;
+ wpabuf_free(auth->resp_msg);
+ auth->resp_msg = msg;
+ return 0;
+}
+
+
+struct dpp_authentication *
+dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
+ int qr_mutual, struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ unsigned int freq, const u8 *hdr, const u8 *attr_start,
+ size_t attr_len)
+{
+ EVP_PKEY *pi = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
+ *channel;
+ u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
+ i_bootstrap_len, channel_len;
+ struct dpp_authentication *auth = NULL;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Request");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+ wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ auth = dpp_alloc_auth(dpp, msg_ctx);
+ if (!auth)
+ goto fail;
+ if (peer_bi && peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
+ auth->peer_bi = peer_bi;
+ auth->own_bi = own_bi;
+ auth->curve = own_bi->curve;
+ auth->curr_freq = freq;
+
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version && DPP_VERSION > 1) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ goto fail;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
+ channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
+ &channel_len);
+ if (channel) {
+ int neg_freq;
+
+ if (channel_len < 2) {
+ dpp_auth_fail(auth, "Too short Channel attribute");
+ goto fail;
+ }
+
+ neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
+ channel[0], channel[1], neg_freq);
+ if (neg_freq < 0) {
+ dpp_auth_fail(auth,
+ "Unsupported Channel attribute value");
+ goto fail;
+ }
+
+ if (auth->curr_freq != (unsigned int) neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Changing negotiation channel from %u MHz to %u MHz",
+ freq, neg_freq);
+ auth->curr_freq = neg_freq;
+ }
+ }
+
+ i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
+ &i_proto_len);
+ if (!i_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Initiator Protocol Key attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
+ i_proto, i_proto_len);
+
+ /* M = bR * PI */
+ pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
+ if (!pi) {
+ dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
+ goto fail;
+ }
+ dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
+
+ if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
+ goto fail;
+ auth->secret_len = secret_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
+ auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
+
+ if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
+
+ i_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_CAPABILITIES,
+ &i_capab_len);
+ if (!i_capab || i_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid I-capabilities");
+ goto fail;
+ }
+ auth->i_capab = i_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ unwrapped = NULL;
+
+ switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
+ case DPP_CAPAB_ENROLLEE:
+ if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Configurator role");
+ goto not_compatible;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+ auth->configurator = 1;
+ break;
+ case DPP_CAPAB_CONFIGURATOR:
+ if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Enrollee role");
+ goto not_compatible;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+ auth->configurator = 0;
+ break;
+ case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
+ if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+ auth->configurator = 0;
+ } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+ auth->configurator = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Configurator/Enrollee role");
+ goto not_compatible;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
+ auth->i_capab & DPP_CAPAB_ROLE_MASK);
+ goto fail;
+ }
+
+ auth->peer_protocol_key = pi;
+ pi = NULL;
+ if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
+ char hex[SHA256_MAC_LEN * 2 + 1];
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
+ if (dpp_auth_build_resp_status(auth,
+ DPP_STATUS_RESPONSE_PENDING) < 0)
+ goto fail;
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
+ auth->response_pending = 1;
+ os_memcpy(auth->waiting_pubkey_hash,
+ i_bootstrap, i_bootstrap_len);
+ wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
+ i_bootstrap_len);
+ } else {
+ hex[0] = '\0';
+ }
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
+ "%s", hex);
+ return auth;
+ }
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ goto fail;
+
+ return auth;
+
+not_compatible:
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
+ "i-capab=0x%02x", auth->i_capab);
+ if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
+ auth->configurator = 1;
+ else
+ auth->configurator = 0;
+ auth->peer_protocol_key = pi;
+ pi = NULL;
+ if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
+ goto fail;
+
+ auth->remove_on_tx_status = 1;
+ return auth;
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ EVP_PKEY_free(pi);
+ EVP_PKEY_CTX_free(ctx);
+ dpp_auth_deinit(auth);
+ return NULL;
+}
+
+
+int dpp_notify_new_qr_code(struct dpp_authentication *auth,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (!auth || !auth->response_pending ||
+ os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0)
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
+ MACSTR, MAC2STR(auth->peer_mac_addr));
+ auth->peer_bi = peer_bi;
+
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ return -1;
+
+ return 1;
+}
+
+
+static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+ u8 i_auth[4 + DPP_MAX_HASH_LEN];
+ size_t i_auth_len;
+ u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
+ size_t r_nonce_len;
+ const u8 *addr[2];
+ size_t len[2], attr_len;
+ u8 *wrapped_i_auth;
+ u8 *wrapped_r_nonce;
+ u8 *attr_start, *attr_end;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
+
+ i_auth_len = 4 + auth->curve->hash_len;
+ r_nonce_len = 4 + auth->curve->nonce_len;
+ /* Build DPP Authentication Confirmation frame attributes */
+ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+ 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
+ if (!msg)
+ goto fail;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ if (auth->own_bi)
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
+ goto skip_wrapped_data;
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ i_auth_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (status == DPP_STATUS_OK) {
+ /* I-auth wrapped with ke */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
+ wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ goto skip_i_auth;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
+ * 1) */
+ WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
+ WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
+ if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
+ i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+skip_i_auth:
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ i_auth, i_auth_len,
+ 2, addr, len, wrapped_i_auth) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
+ wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+ } else {
+ /* R-nonce wrapped with k2 */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
+ wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
+
+ WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
+ WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
+ os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
+
+ if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
+ r_nonce, r_nonce_len,
+ 2, addr, len, wrapped_r_nonce) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
+ wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Confirmation frame attributes",
+ msg);
+ if (status == DPP_STATUS_OK)
+ dpp_auth_success(auth);
+
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (auth->own_bi)
+ return 0; /* already generated */
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return -1;
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(bi) < 0)
+ goto fail;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Auto-generated own bootstrapping key info: URI %s",
+ bi->uri);
+
+ auth->tmp_own_bi = auth->own_bi = bi;
+
+ return 0;
+fail:
+ dpp_bootstrap_info_free(bi);
+ return -1;
+}
+
+
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ u8 dpp_allowed_roles,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ struct dpp_authentication *auth;
+ size_t nonce_len;
+ size_t secret_len;
+ struct wpabuf *pi = NULL;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ auth = dpp_alloc_auth(dpp, msg_ctx);
+ if (!auth)
+ return NULL;
+ if (peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
+ auth->initiator = 1;
+ auth->waiting_auth_resp = 1;
+ auth->allowed_roles = dpp_allowed_roles;
+ auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
+ auth->peer_bi = peer_bi;
+ auth->own_bi = own_bi;
+ auth->curve = peer_bi->curve;
+
+ if (dpp_autogen_bootstrap_key(auth) < 0 ||
+ dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->i_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate I-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->i_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!auth->own_protocol_key)
+ goto fail;
+
+ pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pi)
+ goto fail;
+
+ /* ECDH: M = pI * BR */
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
+ auth->Mx, &secret_len) < 0)
+ goto fail;
+ auth->secret_len = secret_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
+ auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
+
+ if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
+ wpabuf_free(pi);
+ pi = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
+ wpabuf_free(pi);
+ pi = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
+ neg_freq = 0;
+ auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
+ i_pubkey_hash, neg_freq);
+ if (!auth->req_msg)
+ goto fail;
+
+out:
+ wpabuf_free(pi);
+ return auth;
+fail:
+ dpp_auth_deinit(auth);
+ auth = NULL;
+ goto out;
+}
+static void
+dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len,
+ const u8 *wrapped_data, u16 wrapped_data_len,
+ enum dpp_status_error status)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *i_nonce, *r_capab;
+ u16 i_nonce_len, r_capab_len;
+
+ if (status == DPP_STATUS_NOT_COMPATIBLE) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported incompatible roles");
+ } else if (status == DPP_STATUS_RESPONSE_PENDING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported more time needed");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported failure (status %d)",
+ status);
+ dpp_auth_fail(auth, "Responder reported failure");
+ return;
+ }
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
+ dpp_auth_fail(auth, "I-nonce mismatch");
+ goto fail;
+ }
+
+ r_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_CAPABILITIES,
+ &r_capab_len);
+ if (!r_capab || r_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
+ goto fail;
+ }
+ auth->r_capab = r_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
+ if (status == DPP_STATUS_NOT_COMPATIBLE) {
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
+ "r-capab=0x%02x", auth->r_capab);
+ } else if (status == DPP_STATUS_RESPONSE_PENDING) {
+ u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+
+ if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
+ role);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue waiting for full DPP Authentication Response");
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_RESPONSE_PENDING "%s",
+ auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
+ }
+ }
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+}
+
+
+struct wpabuf *
+dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ EVP_PKEY *pr;
+ size_t secret_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL, *unwrapped2 = NULL;
+ size_t unwrapped_len = 0, unwrapped2_len = 0;
+ const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
+ *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
+ u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
+ r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
+ wrapped2_len, r_auth_len;
+ u8 r_auth2[DPP_MAX_HASH_LEN];
+ u8 role;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Response");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->initiator || !auth->peer_bi || auth->reconfig) {
+ dpp_auth_fail(auth, "Unexpected Authentication Response");
+ return NULL;
+ }
+
+ auth->waiting_auth_resp = 0;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ r_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Unexpected Responder Bootstrapping Key Hash value");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Expected Responder Bootstrapping Key Hash",
+ auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ return NULL;
+ }
+
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap) {
+ if (i_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP,
+ "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+ if (!auth->own_bi ||
+ os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash attribute did not match");
+ return NULL;
+ }
+ } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
+ /* PKEX bootstrapping mandates use of mutual authentication */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return NULL;
+ } else if (auth->own_bi &&
+ auth->own_bi->type == DPP_BOOTSTRAP_NFC_URI &&
+ auth->own_bi->nfc_negotiated) {
+ /* NFC negotiated connection handover bootstrapping mandates
+ * use of mutual authentication */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version && DPP_VERSION > 1) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ return NULL;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ auth->auth_resp_status = status[0];
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_resp_rx_status(auth, hdr, attr_start,
+ attr_len, wrapped_data,
+ wrapped_data_len, status[0]);
+ return NULL;
+ }
+
+ if (!i_bootstrap && auth->own_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder decided not to use mutual authentication");
+ auth->own_bi = NULL;
+ }
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
+ auth->own_bi != NULL);
+
+ r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
+ &r_proto_len);
+ if (!r_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
+ r_proto, r_proto_len);
+
+ /* N = pI * PR */
+ pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
+ if (!pr) {
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key");
+ return NULL;
+ }
+ dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
+
+ if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
+ dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+ goto fail;
+ }
+ EVP_PKEY_free(auth->peer_protocol_key);
+ auth->peer_protocol_key = pr;
+ pr = NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
+ auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
+
+ if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
+ &r_nonce_len);
+ if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
+ os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
+ dpp_auth_fail(auth, "I-nonce mismatch");
+ goto fail;
+ }
+
+ if (auth->own_bi) {
+ /* Mutual authentication */
+ if (dpp_auth_derive_l_initiator(auth) < 0)
+ goto fail;
+ }
+
+ r_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_CAPABILITIES,
+ &r_capab_len);
+ if (!r_capab || r_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
+ goto fail;
+ }
+ auth->r_capab = r_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
+ role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+ if ((auth->allowed_roles ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
+ (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
+ /* Peer selected its role, so move from "either role" to the
+ * role that is compatible with peer's selection. */
+ auth->configurator = role == DPP_CAPAB_ENROLLEE;
+ wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
+ auth->configurator ? "Configurator" : "Enrollee");
+ } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+ wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Unexpected role in R-capabilities 0x%02x",
+ role);
+ if (role != DPP_CAPAB_ENROLLEE &&
+ role != DPP_CAPAB_CONFIGURATOR)
+ goto fail;
+ bin_clear_free(unwrapped, unwrapped_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
+ }
+
+ wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
+ if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Secondary Wrapped Data");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped2, wrapped2_len);
+
+ if (dpp_derive_bk_ke(auth) < 0)
+ goto fail;
+
+ unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
+ unwrapped2 = os_malloc(unwrapped2_len);
+ if (!unwrapped2)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped2, wrapped2_len,
+ 0, NULL, NULL, unwrapped2) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped2, unwrapped2_len);
+
+ if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
+ dpp_auth_fail(auth,
+ "Invalid attribute in secondary unwrapped data");
+ goto fail;
+ }
+
+ r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
+ &r_auth_len);
+ if (!r_auth || r_auth_len != auth->curve->hash_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Responder Authenticating Tag");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
+ r_auth, r_auth_len);
+ /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ if (dpp_gen_r_auth(auth, r_auth2) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
+ r_auth2, r_auth_len);
+ if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
+ dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
+ }
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - Authentication Response in place of Confirm");
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ return NULL;
+ return wpabuf_dup(auth->resp_msg);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return dpp_auth_build_conf(auth, DPP_STATUS_OK);
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+ EVP_PKEY_free(pr);
+ return NULL;
+}
+
+
+static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len,
+ const u8 *wrapped_data,
+ u16 wrapped_data_len,
+ enum dpp_status_error status)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *r_nonce;
+ u16 r_nonce_len;
+
+ /* Authentication Confirm failure cases are expected to include
+ * {R-nonce}k2 in the Wrapped Data attribute. */
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped) {
+ dpp_auth_fail(auth, "Authentication failed");
+ goto fail;
+ }
+ if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
+ &r_nonce_len);
+ if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
+ goto fail;
+ }
+ if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
+ wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
+ r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
+ auth->r_nonce, r_nonce_len);
+ dpp_auth_fail(auth, "R-nonce mismatch");
+ goto fail;
+ }
+
+ if (status == DPP_STATUS_NOT_COMPATIBLE)
+ dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
+ else if (status == DPP_STATUS_AUTH_FAILURE)
+ dpp_auth_fail(auth, "Peer reported authentication failure)");
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return -1;
+}
+
+
+int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
+ u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
+ i_auth_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ u8 i_auth2[DPP_MAX_HASH_LEN];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ return -1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf ||
+ auth->reconfig) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
+ auth->initiator, !!auth->own_bi,
+ auth->waiting_auth_conf);
+ dpp_auth_fail(auth, "Unexpected Authentication Confirm");
+ return -1;
+ }
+
+ auth->waiting_auth_conf = 0;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ r_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Expected Responder Bootstrapping Key Hash",
+ auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ dpp_auth_fail(auth,
+ "Responder Bootstrapping Key Hash mismatch");
+ return -1;
+ }
+
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap) {
+ if (i_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP,
+ "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+ if (!auth->peer_bi ||
+ os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash mismatch");
+ return -1;
+ }
+ } else if (auth->peer_bi) {
+ /* Mutual authentication and peer did not include its
+ * Bootstrapping Key Hash attribute. */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
+ status[0] == DPP_STATUS_AUTH_FAILURE)
+ return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
+ attr_len, wrapped_data,
+ wrapped_data_len, status[0]);
+
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth, "Authentication failed");
+ return -1;
+ }
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ return -1;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
+ &i_auth_len);
+ if (!i_auth || i_auth_len != auth->curve->hash_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Initiator Authenticating Tag");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
+ i_auth, i_auth_len);
+ /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
+ if (dpp_gen_i_auth(auth, i_auth2) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
+ i_auth2, i_auth_len);
+ if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
+ dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
+ goto fail;
+ }
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ dpp_auth_success(auth);
+ return 0;
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return -1;
+}
diff --git a/contrib/wpa/src/common/dpp_backup.c b/contrib/wpa/src/common/dpp_backup.c
new file mode 100644
index 000000000000..947a5e9ea33e
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_backup.c
@@ -0,0 +1,1265 @@
+/*
+ * DPP configurator backup
+ * Copyright (c) 2019-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+
+#include "utils/common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "tls/asn1.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+#ifdef CONFIG_DPP2
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
+#endif
+
+
+void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
+{
+ while (key) {
+ struct dpp_asymmetric_key *next = key->next;
+
+ EVP_PKEY_free(key->csign);
+ EVP_PKEY_free(key->pp_key);
+ str_clear_free(key->config_template);
+ str_clear_free(key->connector_template);
+ os_free(key);
+ key = next;
+ }
+}
+
+
+static struct wpabuf * dpp_build_conf_params(struct dpp_configurator *conf)
+{
+ struct wpabuf *buf, *priv_key = NULL;
+ size_t len;
+ /* TODO: proper template values */
+ const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
+ const char *connector_template = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ if (!conf->pp_key)
+ return NULL;
+ eckey = EVP_PKEY_get0_EC_KEY(conf->pp_key);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!priv_key)
+ goto fail;
+
+ len = 100 + os_strlen(conf_template);
+ if (connector_template)
+ len += os_strlen(connector_template);
+ if (priv_key)
+ len += wpabuf_len(priv_key);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ goto fail;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(buf, priv_key);
+
+ asn1_put_utf8string(buf, conf_template);
+ if (connector_template)
+ asn1_put_utf8string(buf, connector_template);
+ wpabuf_clear_free(priv_key);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+fail:
+ wpabuf_clear_free(priv_key);
+ return NULL;
+}
+
+
+static struct wpabuf * dpp_build_attribute(struct dpp_configurator *conf)
+{
+ struct wpabuf *conf_params, *attr;
+
+ /*
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ */
+ conf_params = dpp_build_conf_params(conf);
+ conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
+ ASN1_TAG_SET);
+ if (!conf_params)
+ return NULL;
+
+ attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
+ if (!attr) {
+ wpabuf_clear_free(conf_params);
+ return NULL;
+ }
+
+ asn1_put_oid(attr, &asn1_dpp_config_params_oid);
+ wpabuf_put_buf(attr, conf_params);
+ wpabuf_clear_free(conf_params);
+
+ return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
+{
+ const struct asn1_oid *oid;
+ struct wpabuf *params, *res;
+
+ switch (curve->ike_group) {
+ case 19:
+ oid = &asn1_prime256v1_oid;
+ break;
+ case 20:
+ oid = &asn1_secp384r1_oid;
+ break;
+ case 21:
+ oid = &asn1_secp521r1_oid;
+ break;
+ case 28:
+ oid = &asn1_brainpoolP256r1_oid;
+ break;
+ case 29:
+ oid = &asn1_brainpoolP384r1_oid;
+ break;
+ case 30:
+ oid = &asn1_brainpoolP512r1_oid;
+ break;
+ default:
+ return NULL;
+ }
+
+ params = wpabuf_alloc(20);
+ if (!params)
+ return NULL;
+ asn1_put_oid(params, oid); /* namedCurve */
+
+ res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
+ wpabuf_free(params);
+ return res;
+}
+
+
+static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
+{
+ struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ alg = dpp_build_key_alg(auth->conf->curve);
+
+ /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
+ attr = dpp_build_attribute(auth->conf);
+ attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
+ if (!priv_key || !attr || !alg)
+ goto fail;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+
+ key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
+ wpabuf_len(attr));
+ if (!key)
+ goto fail;
+
+ asn1_put_integer(key, 0); /* version = v1(0) */
+
+ /* PrivateKeyAlgorithmIdentifier */
+ wpabuf_put_buf(key, alg);
+
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(key, priv_key);
+
+ /* [0] Attributes OPTIONAL */
+ asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
+ wpabuf_put_buf(key, attr);
+
+fail:
+ wpabuf_clear_free(attr);
+ wpabuf_clear_free(priv_key);
+ wpabuf_free(alg);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ *
+ * OneAsymmetricKey ::= SEQUENCE
+ */
+ return asn1_encaps(asn1_encaps(key,
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
+ size_t hash_len)
+{
+ struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
+ const struct asn1_oid *oid;
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_pbkdf2_hmac_sha256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_pbkdf2_hmac_sha384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_pbkdf2_hmac_sha512_oid;
+ else
+ goto fail;
+ prf = asn1_build_alg_id(oid, NULL);
+ if (!prf)
+ goto fail;
+ params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
+ if (!params)
+ goto fail;
+ asn1_put_octet_string(params, salt); /* salt.specified */
+ asn1_put_integer(params, 1000); /* iterationCount */
+ asn1_put_integer(params, hash_len); /* keyLength */
+ wpabuf_put_buf(params, prf);
+ params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ if (!params)
+ goto fail;
+ buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
+fail:
+ wpabuf_free(params);
+ wpabuf_free(prf);
+ return buf;
+}
+
+
+static struct wpabuf *
+dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
+ *key_enc_alg = NULL, *salt;
+ u8 kek[DPP_MAX_HASH_LEN];
+ u8 key[DPP_MAX_HASH_LEN];
+ size_t key_len;
+ int res;
+
+ salt = wpabuf_alloc(64);
+ if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
+
+ key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
+ kek, hash_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, hash_len);
+
+ enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
+ if (!enc_key ||
+ aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
+ wpabuf_len(cont_enc_key), 0, NULL, NULL,
+ wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
+ key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
+ if (!key_der_alg || !key_enc_alg)
+ goto fail;
+ pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
+ wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
+ if (!pwri)
+ goto fail;
+
+ /* version = 0 */
+ asn1_put_integer(pwri, 0);
+
+ /* [0] KeyDerivationAlgorithmIdentifier */
+ asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
+ wpabuf_len(key_der_alg));
+ wpabuf_put_buf(pwri, key_der_alg);
+
+ /* KeyEncryptionAlgorithmIdentifier */
+ wpabuf_put_buf(pwri, key_enc_alg);
+
+ /* EncryptedKey ::= OCTET STRING */
+ asn1_put_octet_string(pwri, enc_key);
+
+fail:
+ wpabuf_clear_free(key_der_alg);
+ wpabuf_free(key_enc_alg);
+ wpabuf_free(enc_key);
+ wpabuf_free(salt);
+ forced_memzero(kek, sizeof(kek));
+ return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf *
+dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *pwri;
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
+ return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
+}
+
+
+static struct wpabuf *
+dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
+ *enc_alg;
+ const struct asn1_oid *oid;
+ size_t enc_cont_len;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_aes_siv_cmac_aead_256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_aes_siv_cmac_aead_384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_aes_siv_cmac_aead_512_oid;
+ else
+ return NULL;
+
+ key_pkg = dpp_build_key_pkg(auth);
+ enc_alg = asn1_build_alg_id(oid, NULL);
+ if (!key_pkg || !enc_alg)
+ goto fail;
+
+ wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg);
+
+ enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
+ enc_cont = wpabuf_alloc(enc_cont_len);
+ if (!enc_cont ||
+ aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
+ wpabuf_head(key_pkg), wpabuf_len(key_pkg),
+ 0, NULL, NULL,
+ wpabuf_put(enc_cont, enc_cont_len)) < 0)
+ goto fail;
+
+ enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
+ wpabuf_len(enc_cont));
+ if (!enc_cont_info)
+ goto fail;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ wpabuf_put_buf(enc_cont_info, enc_alg);
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
+ wpabuf_len(enc_cont));
+ wpabuf_put_buf(enc_cont_info, enc_cont);
+
+fail:
+ wpabuf_clear_free(key_pkg);
+ wpabuf_free(enc_cont);
+ wpabuf_free(enc_alg);
+ return enc_cont_info;
+}
+
+
+static struct wpabuf * dpp_gen_random(size_t len)
+{
+ struct wpabuf *key;
+
+ key = wpabuf_alloc(len);
+ if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
+ wpabuf_free(key);
+ key = NULL;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
+ return key;
+}
+
+
+struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
+{
+ struct wpabuf *env = NULL;
+ struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
+ struct wpabuf *cont_enc_key = NULL;
+ size_t hash_len;
+
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
+ return NULL;
+ }
+
+ if (!auth->provision_configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator provisioning not allowed");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
+
+ hash_len = auth->conf->curve->hash_len;
+ cont_enc_key = dpp_gen_random(hash_len);
+ if (!cont_enc_key)
+ goto fail;
+ recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
+ enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
+ if (!recipient_info || !enc_cont_info)
+ goto fail;
+
+ env = wpabuf_alloc(wpabuf_len(recipient_info) +
+ wpabuf_len(enc_cont_info) +
+ 100);
+ if (!env)
+ goto fail;
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+
+ /* EnvelopedData.version = 3 */
+ asn1_put_integer(env, 3);
+
+ /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
+ asn1_put_set(env, recipient_info);
+
+ /* EncryptedContentInfo ::= SEQUENCE */
+ asn1_put_sequence(env, enc_cont_info);
+
+ env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
+out:
+ wpabuf_clear_free(cont_enc_key);
+ wpabuf_clear_free(recipient_info);
+ wpabuf_free(enc_cont_info);
+ return env;
+fail:
+ wpabuf_free(env);
+ env = NULL;
+ goto out;
+}
+
+
+struct dpp_enveloped_data {
+ const u8 *enc_cont;
+ size_t enc_cont_len;
+ const u8 *enc_key;
+ size_t enc_key_len;
+ const u8 *salt;
+ size_t pbkdf2_key_len;
+ size_t prf_hash_len;
+};
+
+
+static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *end = pos + len;
+ const u8 *next, *e_end;
+ struct asn1_oid oid;
+ int val;
+ const u8 *params;
+ size_t params_len;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 3)) {
+ asn1_unexpected(&hdr, "DPP: Expected CHOICE [3] (pwri)");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
+ pos, end - pos);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected keyDerivationAlgorithm [0]");
+ return -1;
+ }
+ pos = hdr.payload;
+ e_end = pos + hdr.length;
+
+ /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
+ &next) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+ if (!params ||
+ asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected OCTETSTRING (salt.specified)");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
+ hdr.payload, hdr.length);
+ if (hdr.length != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
+ hdr.length);
+ return -1;
+ }
+ data->salt = hdr.payload;
+ pos = hdr.payload + hdr.length;
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 1000) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 32 && val != 48 && val != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
+ return -1;
+ }
+ data->pbkdf2_key_len = val;
+
+ if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
+ return -1;
+ }
+ if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
+ data->prf_hash_len = 32;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
+ data->prf_hash_len = 48;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
+ data->prf_hash_len = 64;
+ } else {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
+ buf);
+ return -1;
+ }
+
+ pos = next;
+
+ /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
+ *
+ * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
+ * id-alg-AES-SIV-CMAC-aed-512. */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * encryptedKey EncryptedKey
+ *
+ * EncryptedKey ::= OCTET STRING
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected OCTETSTRING (pwri.encryptedKey)");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
+ hdr.payload, hdr.length);
+ data->enc_key = hdr.payload;
+ data->enc_key_len = hdr.length;
+
+ return 0;
+}
+
+
+static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ return -1;
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
+ hdr.payload, hdr.length);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after EncryptedContentInfo",
+ pos, end - pos);
+ return -1;
+ }
+
+ end = pos;
+ pos = hdr.payload;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
+ return -1;
+ }
+ if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
+ return -1;
+ }
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+ /* ignore optional parameters */
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected [0] IMPLICIT (EncryptedContent)");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
+ hdr.payload, hdr.length);
+ data->enc_cont = hdr.payload;
+ data->enc_cont_len = hdr.length;
+ return 0;
+}
+
+
+static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ int val;
+
+ os_memset(data, 0, sizeof(*data));
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * CMSVersion ::= INTEGER
+ *
+ * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+ if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+ if (end < env_data + env_data_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after DPPEnvelopedData",
+ end, env_data + env_data_len - end);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 3) {
+ wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected SET (RecipientInfos)");
+ return -1;
+ }
+
+ if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
+ return -1;
+ return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
+ data);
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = buf, *end = buf + len, *next;
+ int val;
+ const u8 *params;
+ size_t params_len;
+ struct asn1_oid oid;
+ char txt[80];
+ struct dpp_asymmetric_key *key;
+ EC_KEY *eckey;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ goto fail;
+ pos = hdr.payload;
+
+ /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ goto fail;
+ if (val != 0 && val != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
+ val);
+ goto fail;
+ }
+
+ /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
+ &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
+ txt);
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
+ params, params_len);
+ /*
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * -- implicitCurve NULL
+ * -- specifiedCurve SpecifiedECDomain}
+ */
+ if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not parse ECParameters.namedCurve");
+ goto fail;
+ }
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
+ /* Assume the curve is identified within ECPrivateKey, so that this
+ * separate indication is not really needed. */
+
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected OCTETSTRING (PrivateKey)");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->csign = EVP_PKEY_new();
+ if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
+
+ /*
+ * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ *
+ * Exactly one instance of type Attribute in OneAsymmetricKey.
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr, "DPP: Expected [0] Attributes");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
+ hdr.payload, hdr.length);
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr, "DPP: Expected SET (Attributes)");
+ goto fail;
+ }
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
+ * aa-DPPConfigurationParameters,
+ * ... -- For local profiles
+ * }
+ *
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ *
+ * Exactly one instance of ATTRIBUTE in attrValues.
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of ATTRIBUTE",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected Attribute identifier %s", txt);
+ goto fail;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr, "DPP: Expected SET (Attribute)");
+ goto fail;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
+ pos, end - pos);
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data after DPPConfigurationParameters",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr, "DPP: Expected OCTETSTRING (PrivateKey)");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: privacyProtectionKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->pp_key = EVP_PKEY_new();
+ if (!key->pp_key || EVP_PKEY_assign_EC_KEY(key->pp_key, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received privacyProtectionKey",
+ key->pp_key);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_utf8string(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected UTF8STRING (configurationTemplate)");
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
+ hdr.payload, hdr.length);
+ key->config_template = os_zalloc(hdr.length + 1);
+ if (!key->config_template)
+ goto fail;
+ os_memcpy(key->config_template, hdr.payload, hdr.length);
+
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_utf8string(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DPP: Expected UTF8STRING (connectorTemplate)");
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
+ hdr.payload, hdr.length);
+ key->connector_template = os_zalloc(hdr.length + 1);
+ if (!key->connector_template)
+ goto fail;
+ os_memcpy(key->connector_template, hdr.payload, hdr.length);
+ }
+
+ return key;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
+ dpp_free_asymmetric_key(key);
+ return NULL;
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
+ struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg, key_pkg_len);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ */
+ while (pos < end) {
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
+ !(key = dpp_parse_one_asymmetric_key(hdr.payload,
+ hdr.length))) {
+ dpp_free_asymmetric_key(first);
+ return NULL;
+ }
+ if (!last) {
+ first = last = key;
+ } else {
+ last->next = key;
+ last = key;
+ }
+ }
+
+ return first;
+}
+
+
+int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+ const u8 *env_data, size_t env_data_len)
+{
+ u8 key[DPP_MAX_HASH_LEN];
+ size_t key_len;
+ u8 kek[DPP_MAX_HASH_LEN];
+ u8 cont_encr_key[DPP_MAX_HASH_LEN];
+ size_t cont_encr_key_len;
+ int res;
+ u8 *key_pkg;
+ size_t key_pkg_len;
+ struct dpp_enveloped_data data;
+ struct dpp_asymmetric_key *keys;
+
+ wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
+
+ if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
+ return -1;
+
+ key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
+ kek, data.pbkdf2_key_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, data.pbkdf2_key_len);
+
+ if (data.enc_key_len < AES_BLOCK_SIZE ||
+ data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
+ return -1;
+ }
+ res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
+ data.enc_key, data.enc_key_len,
+ 0, NULL, NULL, cont_encr_key);
+ forced_memzero(kek, data.pbkdf2_key_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedKey failed");
+ return -1;
+ }
+ cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
+ cont_encr_key, cont_encr_key_len);
+
+ if (data.enc_cont_len < AES_BLOCK_SIZE)
+ return -1;
+ key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
+ key_pkg = os_malloc(key_pkg_len);
+ if (!key_pkg)
+ return -1;
+ res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
+ data.enc_cont, data.enc_cont_len,
+ 0, NULL, NULL, key_pkg);
+ forced_memzero(cont_encr_key, cont_encr_key_len);
+ if (res < 0) {
+ bin_clear_free(key_pkg, key_pkg_len);
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedContent failed");
+ return -1;
+ }
+
+ keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
+ bin_clear_free(key_pkg, key_pkg_len);
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
+ auth->conf_key_pkg = keys;
+
+ return keys != NULL;
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/common/dpp_crypto.c b/contrib/wpa/src/common/dpp_crypto.c
new file mode 100644
index 000000000000..c75fc78711a8
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_crypto.c
@@ -0,0 +1,3329 @@
+/*
+ * DPP crypto functionality
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "utils/json.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+
+static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
+ const BIGNUM **ps)
+{
+ if (pr)
+ *pr = sig->r;
+ if (ps)
+ *ps = sig->s;
+}
+
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
+#endif
+
+static const struct dpp_curve_params dpp_curves[] = {
+ /* The mandatory to support and the default NIST P-256 curve needs to
+ * be the first entry on this list. */
+ { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
+ { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
+ { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
+ { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
+ { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
+ { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
+ { NULL, 0, 0, 0, 0, NULL, 0, NULL }
+};
+
+
+const struct dpp_curve_params * dpp_get_curve_name(const char *name)
+{
+ int i;
+
+ if (!name)
+ return &dpp_curves[0];
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (os_strcmp(name, dpp_curves[i].name) == 0 ||
+ (dpp_curves[i].jwk_crv &&
+ os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (dpp_curves[i].jwk_crv &&
+ os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+static const struct dpp_curve_params *
+dpp_get_curve_oid(const ASN1_OBJECT *poid)
+{
+ ASN1_OBJECT *oid;
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ oid = OBJ_txt2obj(dpp_curves[i].name, 0);
+ if (oid && OBJ_cmp(poid, oid) == 0)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+const struct dpp_curve_params * dpp_get_curve_nid(int nid)
+{
+ int i, tmp;
+
+ if (!nid)
+ return NULL;
+ for (i = 0; dpp_curves[i].name; i++) {
+ tmp = OBJ_txt2nid(dpp_curves[i].name);
+ if (tmp == nid)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (dpp_curves[i].ike_group == group)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+void dpp_debug_print_point(const char *title, const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ BIGNUM *x, *y;
+ BN_CTX *ctx;
+ char *x_str = NULL, *y_str = NULL;
+
+ if (!wpa_debug_show_keys)
+ return;
+
+ ctx = BN_CTX_new();
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !x || !y ||
+ EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
+ goto fail;
+
+ x_str = BN_bn2hex(x);
+ y_str = BN_bn2hex(y);
+ if (!x_str || !y_str)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
+
+fail:
+ OPENSSL_free(x_str);
+ OPENSSL_free(y_str);
+ BN_free(x);
+ BN_free(y);
+ BN_CTX_free(ctx);
+}
+
+
+void dpp_debug_print_key(const char *title, EVP_PKEY *key)
+{
+ EC_KEY *eckey;
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+ unsigned char *der = NULL;
+ int der_len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ EVP_PKEY_print_private(out, key, 0, NULL);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
+ }
+ os_free(txt);
+ }
+ BIO_free(out);
+
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!eckey)
+ return;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (group && point)
+ dpp_debug_print_point(title, group, point);
+
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
+ OPENSSL_free(der);
+ if (der_len <= 0) {
+ der = NULL;
+ der_len = i2d_EC_PUBKEY(eckey, &der);
+ if (der_len > 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
+ OPENSSL_free(der);
+ }
+
+ EC_KEY_free(eckey);
+}
+
+
+static int dpp_hash_vector(const struct dpp_curve_params *curve,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ if (curve->hash_len == 32)
+ return sha256_vector(num_elem, addr, len, mac);
+ if (curve->hash_len == 48)
+ return sha384_vector(num_elem, addr, len, mac);
+ if (curve->hash_len == 64)
+ return sha512_vector(num_elem, addr, len, mac);
+ return -1;
+}
+
+
+int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
+ const char *label, u8 *out, size_t outlen)
+{
+ if (hash_len == 32)
+ return hmac_sha256_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ if (hash_len == 48)
+ return hmac_sha384_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ if (hash_len == 64)
+ return hmac_sha512_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ return -1;
+}
+
+
+int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+ mac);
+ if (hash_len == 48)
+ return hmac_sha384_vector(key, key_len, num_elem, addr, len,
+ mac);
+ if (hash_len == 64)
+ return hmac_sha512_vector(key, key_len, num_elem, addr, len,
+ mac);
+ return -1;
+}
+
+
+static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
+ const u8 *data, size_t data_len, u8 *mac)
+{
+ if (hash_len == 32)
+ return hmac_sha256(key, key_len, data, data_len, mac);
+ if (hash_len == 48)
+ return hmac_sha384(key, key_len, data, data_len, mac);
+ if (hash_len == 64)
+ return hmac_sha512(key, key_len, data, data_len, mac);
+ return -1;
+}
+
+
+#ifdef CONFIG_DPP2
+
+static int dpp_pbkdf2_f(size_t hash_len,
+ const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len,
+ unsigned int iterations, unsigned int count, u8 *digest)
+{
+ unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
+ unsigned int i;
+ size_t j;
+ u8 count_buf[4];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = salt;
+ len[0] = salt_len;
+ addr[1] = count_buf;
+ len[1] = 4;
+
+ /* F(P, S, c, i) = U1 xor U2 xor ... Uc
+ * U1 = PRF(P, S || i)
+ * U2 = PRF(P, U1)
+ * Uc = PRF(P, Uc-1)
+ */
+
+ WPA_PUT_BE32(count_buf, count);
+ if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
+ tmp))
+ return -1;
+ os_memcpy(digest, tmp, hash_len);
+
+ for (i = 1; i < iterations; i++) {
+ if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
+ tmp2))
+ return -1;
+ os_memcpy(tmp, tmp2, hash_len);
+ for (j = 0; j < hash_len; j++)
+ digest[j] ^= tmp2[j];
+ }
+
+ return 0;
+}
+
+
+int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len, unsigned int iterations,
+ u8 *buf, size_t buflen)
+{
+ unsigned int count = 0;
+ unsigned char *pos = buf;
+ size_t left = buflen, plen;
+ unsigned char digest[DPP_MAX_HASH_LEN];
+
+ while (left > 0) {
+ count++;
+ if (dpp_pbkdf2_f(hash_len, password, password_len,
+ salt, salt_len, iterations, count, digest))
+ return -1;
+ plen = left > hash_len ? hash_len : left;
+ os_memcpy(pos, digest, plen);
+ pos += plen;
+ left -= plen;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
+{
+ int num_bytes, offset;
+
+ num_bytes = BN_num_bytes(bn);
+ if ((size_t) num_bytes > len)
+ return -1;
+ offset = len - num_bytes;
+ os_memset(pos, 0, offset);
+ BN_bn2bin(bn, pos + offset);
+ return 0;
+}
+
+
+struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
+{
+ int len, res;
+ EC_KEY *eckey;
+ struct wpabuf *buf;
+ unsigned char *pos;
+
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!eckey)
+ return NULL;
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
+ len = i2o_ECPublicKey(eckey, NULL);
+ if (len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to determine public key encoding length");
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(len);
+ if (!buf) {
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, len);
+ res = i2o_ECPublicKey(eckey, &pos);
+ EC_KEY_free(eckey);
+ if (res != len) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to encode public key (res=%d/%d)",
+ res, len);
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (!prefix) {
+ /* Remove 0x04 prefix to match DPP definition */
+ pos = wpabuf_mhead(buf);
+ os_memmove(pos, pos + 1, len - 1);
+ buf->used--;
+ }
+
+ return buf;
+}
+
+
+EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
+ const u8 *buf_x, const u8 *buf_y,
+ size_t len)
+{
+ EC_KEY *eckey = NULL;
+ BN_CTX *ctx;
+ EC_POINT *point = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ ctx = BN_CTX_new();
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: Out of memory");
+ return NULL;
+ }
+
+ point = EC_POINT_new(group);
+ x = BN_bin2bn(buf_x, len, NULL);
+ y = BN_bin2bn(buf_y, len, NULL);
+ if (!point || !x || !y) {
+ wpa_printf(MSG_ERROR, "DPP: Out of memory");
+ goto fail;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx) ||
+ EC_POINT_is_at_infinity(group, point)) {
+ wpa_printf(MSG_ERROR, "DPP: Invalid point");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
+ goto fail;
+ }
+
+out:
+ BN_free(x);
+ BN_free(y);
+ EC_KEY_free(eckey);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+ return pkey;
+fail:
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto out;
+}
+
+
+EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len)
+{
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ EVP_PKEY *pkey = NULL;
+
+ if (len & 1)
+ return NULL;
+
+ eckey = EVP_PKEY_get0_EC_KEY(group_key);
+ if (!eckey) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Could not get EC_KEY from group_key");
+ return NULL;
+ }
+
+ group = EC_KEY_get0_group(eckey);
+ if (group)
+ pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
+ len / 2);
+ else
+ wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
+
+ return pkey;
+}
+
+
+EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
+{
+ EVP_PKEY_CTX *kctx = NULL;
+ EC_KEY *ec_params = NULL;
+ EVP_PKEY *params = NULL, *key = NULL;
+ int nid;
+
+ wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
+
+ nid = OBJ_txt2nid(curve->name);
+ if (nid == NID_undef) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
+ return NULL;
+ }
+
+ ec_params = EC_KEY_new_by_curve_name(nid);
+ if (!ec_params) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate EC_KEY parameters");
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate EVP_PKEY parameters");
+ goto fail;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (!kctx ||
+ EVP_PKEY_keygen_init(kctx) != 1 ||
+ EVP_PKEY_keygen(kctx, &key) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
+ key = NULL;
+ goto fail;
+ }
+
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("Own generated key", key);
+
+fail:
+ EC_KEY_free(ec_params);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ return key;
+}
+
+
+EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len)
+{
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+
+ pkey = EVP_PKEY_new();
+ if (!pkey)
+ return NULL;
+ eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ group = EC_KEY_get0_group(eckey);
+ if (!group) {
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ nid = EC_GROUP_get_curve_name(group);
+ *curve = dpp_get_curve_nid(nid);
+ if (!*curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported curve (nid=%d) in pre-assigned key",
+ nid);
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ return pkey;
+}
+
+
+typedef struct {
+ /* AlgorithmIdentifier ecPublicKey with optional parameters present
+ * as an OID identifying the curve */
+ X509_ALGOR *alg;
+ /* Compressed format public key per ANSI X9.63 */
+ ASN1_BIT_STRING *pub_key;
+} DPP_BOOTSTRAPPING_KEY;
+
+ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
+
+IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
+
+
+static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ const EC_KEY *eckey;
+ struct wpabuf *ret = NULL;
+ size_t len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BN_CTX *ctx;
+ DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
+ int nid;
+
+ ctx = BN_CTX_new();
+ eckey = EVP_PKEY_get0_EC_KEY(key);
+ if (!ctx || !eckey)
+ goto fail;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (!group || !point)
+ goto fail;
+ dpp_debug_print_point("DPP: bootstrap public key", group, point);
+ nid = EC_GROUP_get_curve_name(group);
+
+ bootstrap = DPP_BOOTSTRAPPING_KEY_new();
+ if (!bootstrap ||
+ X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
+ V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
+ goto fail;
+
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ NULL, 0, ctx);
+ if (len == 0)
+ goto fail;
+
+ der = OPENSSL_malloc(len);
+ if (!der)
+ goto fail;
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ der, len, ctx);
+
+ OPENSSL_free(bootstrap->pub_key->data);
+ bootstrap->pub_key->data = der;
+ der = NULL;
+ bootstrap->pub_key->length = len;
+ /* No unused bits */
+ bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to build DER encoded public key");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+fail:
+ DPP_BOOTSTRAPPING_KEY_free(bootstrap);
+ OPENSSL_free(der);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *der;
+ int res;
+
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
+ return -1;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
+ res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
+ if (res < 0)
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ wpabuf_free(der);
+ return res;
+}
+
+
+int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len)
+{
+ char *base64 = NULL;
+ char *pos, *end;
+ size_t len;
+ struct wpabuf *der = NULL;
+
+ bi->curve = dpp_get_curve_name(curve);
+ if (!bi->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
+ return -1;
+ }
+
+ if (privkey)
+ bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
+ else
+ bi->pubkey = dpp_gen_keypair(bi->curve);
+ if (!bi->pubkey)
+ goto fail;
+ bi->own = 1;
+
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
+
+ if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ goto fail;
+ }
+
+ base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
+ wpabuf_free(der);
+ der = NULL;
+ if (!base64)
+ goto fail;
+ pos = base64;
+ end = pos + len;
+ for (;;) {
+ pos = os_strchr(pos, '\n');
+ if (!pos)
+ break;
+ os_memmove(pos, pos + 1, end - pos);
+ }
+ os_free(bi->pk);
+ bi->pk = base64;
+ return 0;
+fail:
+ os_free(base64);
+ wpabuf_free(der);
+ return -1;
+}
+
+
+int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "first intermediate key";
+ int res;
+
+ /* k1 = HKDF(<>, "first intermediate key", M.x) */
+
+ /* HKDF-Extract(<>, M.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
+ k1, hash_len);
+ return 0;
+}
+
+
+int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "second intermediate key";
+ int res;
+
+ /* k2 = HKDF(<>, "second intermediate key", N.x) */
+
+ /* HKDF-Extract(<>, N.x) */
+ os_memset(salt, 0, hash_len);
+ res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
+ if (res < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
+ k2, hash_len);
+ return 0;
+}
+
+
+int dpp_derive_bk_ke(struct dpp_authentication *auth)
+{
+ unsigned int hash_len = auth->curve->hash_len;
+ size_t nonce_len = auth->curve->nonce_len;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
+ const char *info_ke = "DPP Key";
+ int res;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem = 0;
+
+ if (!auth->Mx_len || !auth->Nx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mx/Nx not available - cannot derive ke");
+ return -1;
+ }
+
+ /* bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
+ os_memcpy(nonces, auth->i_nonce, nonce_len);
+ os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
+ addr[num_elem] = auth->Mx;
+ len[num_elem] = auth->Mx_len;
+ num_elem++;
+ addr[num_elem] = auth->Nx;
+ len[num_elem] = auth->Nx_len;
+ num_elem++;
+ if (auth->peer_bi && auth->own_bi) {
+ if (!auth->Lx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Lx not available - cannot derive ke");
+ return -1;
+ }
+ addr[num_elem] = auth->Lx;
+ len[num_elem] = auth->secret_len;
+ num_elem++;
+ }
+ res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
+ num_elem, addr, len, auth->bk);
+ if (res < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x])",
+ auth->bk, hash_len);
+
+ /* ke = HKDF-Expand(bk, "DPP Key", length) */
+ res = dpp_hkdf_expand(hash_len, auth->bk, hash_len, info_ke, auth->ke,
+ hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: ke = HKDF-Expand(bk, \"DPP Key\", length)",
+ auth->ke, hash_len);
+
+ return 0;
+}
+
+
+int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len)
+{
+ EVP_PKEY_CTX *ctx;
+ int ret = -1;
+
+ ERR_clear_error();
+ *secret_len = 0;
+
+ ctx = EVP_PKEY_CTX_new(own, NULL);
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (EVP_PKEY_derive_init(ctx) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: EVP_PKEY_derive_set_peet failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ u8 buf[200];
+ int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
+
+ /* It looks like OpenSSL can return unexpectedly large buffer
+ * need for shared secret from EVP_PKEY_derive(NULL) in some
+ * cases. For example, group 19 has shown cases where secret_len
+ * is set to 72 even though the actual length ends up being
+ * updated to 32 when EVP_PKEY_derive() is called with a buffer
+ * for the value. Work around this by trying to fetch the value
+ * and continue if it is within supported range even when the
+ * initial buffer need is claimed to be larger. */
+ wpa_printf(level,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ if (*secret_len > 200)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
+ buf, *secret_len);
+ os_memcpy(secret, buf, *secret_len);
+ forced_memzero(buf, sizeof(buf));
+ goto done;
+ }
+
+ if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ ret = 0;
+
+fail:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+
+int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = data;
+ len[0] = data_len;
+ if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
+ bi->pubkey_hash, SHA256_MAC_LEN);
+
+ addr[0] = (const u8 *) "chirp";
+ len[0] = 5;
+ addr[1] = data;
+ len[1] = data_len;
+ if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+
+ return 0;
+}
+
+
+int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len)
+{
+ EVP_PKEY *pkey;
+ const unsigned char *p;
+ int res;
+ X509_PUBKEY *pub = NULL;
+ ASN1_OBJECT *ppkalg;
+ const unsigned char *pk;
+ int ppklen;
+ X509_ALGOR *pa;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20800000L)
+ ASN1_OBJECT *pa_oid;
+#else
+ const ASN1_OBJECT *pa_oid;
+#endif
+ const void *pval;
+ int ptype;
+ const ASN1_OBJECT *poid;
+ char buf[100];
+
+ if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ return -1;
+ }
+
+ /* DER encoded ASN.1 SubjectPublicKeyInfo
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ * subjectPublicKey = compressed format public key per ANSI X9.63
+ * algorithm = ecPublicKey (1.2.840.10045.2.1)
+ * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
+ * prime256v1 (1.2.840.10045.3.1.7)
+ */
+
+ p = data;
+ pkey = d2i_PUBKEY(NULL, &p, data_len);
+
+ if (!pkey) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
+ return -1;
+ }
+
+ if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SubjectPublicKeyInfo does not describe an EC key");
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+
+ res = X509_PUBKEY_set(&pub, pkey);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
+ goto fail;
+ }
+
+ res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo parameters");
+ goto fail;
+ }
+ res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo algorithm");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
+ if (os_strcmp(buf, "id-ecPublicKey") != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported SubjectPublicKeyInfo algorithm");
+ goto fail;
+ }
+
+ X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
+ if (ptype != V_ASN1_OBJECT) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
+ goto fail;
+ }
+ poid = pval;
+ res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
+ bi->curve = dpp_get_curve_oid(poid);
+ if (!bi->curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
+ buf);
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
+
+ X509_PUBKEY_free(pub);
+ bi->pubkey = pkey;
+ return 0;
+fail:
+ X509_PUBKEY_free(pub);
+ EVP_PKEY_free(pkey);
+ return -1;
+}
+
+
+static struct wpabuf *
+dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
+ const u8 *prot_hdr, u16 prot_hdr_len,
+ const EVP_MD **ret_md)
+{
+ struct json_token *root, *token;
+ struct wpabuf *kid = NULL;
+
+ root = json_parse((const char *) prot_hdr, prot_hdr_len);
+ if (!root) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: JSON parsing failed for JWS Protected Header");
+ goto fail;
+ }
+
+ if (root->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: JWS Protected Header root is not an object");
+ goto fail;
+ }
+
+ token = json_get_member(root, "typ");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
+ token->string);
+ if (os_strcmp(token->string, "dppCon") != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported JWS Protected Header typ=%s",
+ token->string);
+ goto fail;
+ }
+
+ token = json_get_member(root, "alg");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
+ token->string);
+ if (os_strcmp(token->string, curve->jws_alg) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
+ token->string, curve->jws_alg);
+ goto fail;
+ }
+ if (os_strcmp(token->string, "ES256") == 0 ||
+ os_strcmp(token->string, "BS256") == 0)
+ *ret_md = EVP_sha256();
+ else if (os_strcmp(token->string, "ES384") == 0 ||
+ os_strcmp(token->string, "BS384") == 0)
+ *ret_md = EVP_sha384();
+ else if (os_strcmp(token->string, "ES512") == 0 ||
+ os_strcmp(token->string, "BS512") == 0)
+ *ret_md = EVP_sha512();
+ else
+ *ret_md = NULL;
+ if (!*ret_md) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported JWS Protected Header alg=%s",
+ token->string);
+ goto fail;
+ }
+
+ kid = json_get_member_base64url(root, "kid");
+ if (!kid) {
+ wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
+ goto fail;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
+ kid);
+
+fail:
+ json_free(root);
+ return kid;
+}
+
+
+static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
+{
+ struct wpabuf *uncomp;
+ int res;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+
+ if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
+ return -1;
+ uncomp = dpp_get_pubkey_point(pub, 1);
+ if (!uncomp)
+ return -1;
+ addr[0] = wpabuf_head(uncomp);
+ len[0] = wpabuf_len(uncomp);
+ wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
+ addr[0], len[0]);
+ res = sha256_vector(1, addr, len, hash);
+ wpabuf_free(uncomp);
+ if (res < 0)
+ return -1;
+ if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received hash value does not match calculated public key hash value");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
+ hash, SHA256_MAC_LEN);
+ return -1;
+ }
+ return 0;
+}
+
+
+enum dpp_status_error
+dpp_process_signed_connector(struct dpp_signed_connector_info *info,
+ EVP_PKEY *csign_pub, const char *connector)
+{
+ enum dpp_status_error ret = 255;
+ const char *pos, *end, *signed_start, *signed_end;
+ struct wpabuf *kid = NULL;
+ unsigned char *prot_hdr = NULL, *signature = NULL;
+ size_t prot_hdr_len = 0, signature_len = 0;
+ const EVP_MD *sign_md = NULL;
+ unsigned char *der = NULL;
+ int der_len;
+ int res;
+ EVP_MD_CTX *md_ctx = NULL;
+ ECDSA_SIG *sig = NULL;
+ BIGNUM *r = NULL, *s = NULL;
+ const struct dpp_curve_params *curve;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+
+ eckey = EVP_PKEY_get0_EC_KEY(csign_pub);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ goto fail;
+ nid = EC_GROUP_get_curve_name(group);
+ curve = dpp_get_curve_nid(nid);
+ if (!curve)
+ goto fail;
+ wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
+ os_memset(info, 0, sizeof(*info));
+
+ signed_start = pos = connector;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
+ if (!prot_hdr) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector JWS Protected Header");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: signedConnector - JWS Protected Header",
+ prot_hdr, prot_hdr_len);
+ kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
+ if (!kid) {
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ if (wpabuf_len(kid) != SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
+ (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ pos = end + 1;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing dot(2) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ signed_end = end - 1;
+ info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
+ if (!info->payload) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector JWS Payload");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: signedConnector - JWS Payload",
+ info->payload, info->payload_len);
+ pos = end + 1;
+ signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
+ if (!signature) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector signature");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
+ signature, signature_len);
+
+ if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
+ ret = DPP_STATUS_NO_MATCH;
+ goto fail;
+ }
+
+ if (signature_len & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected signedConnector signature length (%d)",
+ (int) signature_len);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ /* JWS Signature encodes the signature (r,s) as two octet strings. Need
+ * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
+ r = BN_bin2bn(signature, signature_len / 2, NULL);
+ s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
+ sig = ECDSA_SIG_new();
+ if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
+ goto fail;
+ r = NULL;
+ s = NULL;
+
+ der_len = i2d_ECDSA_SIG(sig, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
+ md_ctx = EVP_MD_CTX_create();
+ if (!md_ctx)
+ goto fail;
+
+ ERR_clear_error();
+ if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
+ signed_end - signed_start + 1) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
+ res, ERR_error_string(ERR_get_error(), NULL));
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ ret = DPP_STATUS_OK;
+fail:
+ EVP_MD_CTX_destroy(md_ctx);
+ os_free(prot_hdr);
+ wpabuf_free(kid);
+ os_free(signature);
+ ECDSA_SIG_free(sig);
+ BN_free(r);
+ BN_free(s);
+ OPENSSL_free(der);
+ return ret;
+}
+
+
+enum dpp_status_error
+dpp_check_signed_connector(struct dpp_signed_connector_info *info,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len)
+{
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL;
+ char *signed_connector = NULL;
+ enum dpp_status_error res = DPP_STATUS_INVALID_CONNECTOR;
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to parse local C-sign-key information");
+ goto fail;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
+ peer_connector, peer_connector_len);
+ signed_connector = os_malloc(peer_connector_len + 1);
+ if (!signed_connector)
+ goto fail;
+ os_memcpy(signed_connector, peer_connector, peer_connector_len);
+ signed_connector[peer_connector_len] = '\0';
+ res = dpp_process_signed_connector(info, csign, signed_connector);
+fail:
+ os_free(signed_connector);
+ EVP_PKEY_free(csign);
+ return res;
+}
+
+
+int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
+{
+ struct wpabuf *pix, *prx, *bix, *brx;
+ const u8 *addr[7];
+ size_t len[7];
+ size_t i, num_elem = 0;
+ size_t nonce_len;
+ u8 zero = 0;
+ int res = -1;
+
+ /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ nonce_len = auth->curve->nonce_len;
+
+ if (auth->initiator) {
+ pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ if (auth->own_bi)
+ bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ else
+ bix = NULL;
+ brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ } else {
+ pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (auth->peer_bi)
+ bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ else
+ bix = NULL;
+ brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ }
+ if (!pix || !prx || !brx)
+ goto fail;
+
+ addr[num_elem] = auth->i_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = auth->r_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(pix);
+ len[num_elem] = wpabuf_len(pix) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(prx);
+ len[num_elem] = wpabuf_len(prx) / 2;
+ num_elem++;
+
+ if (bix) {
+ addr[num_elem] = wpabuf_head(bix);
+ len[num_elem] = wpabuf_len(bix) / 2;
+ num_elem++;
+ }
+
+ addr[num_elem] = wpabuf_head(brx);
+ len[num_elem] = wpabuf_len(brx) / 2;
+ num_elem++;
+
+ addr[num_elem] = &zero;
+ len[num_elem] = 1;
+ num_elem++;
+
+ wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
+ res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
+ if (res == 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
+ auth->curve->hash_len);
+fail:
+ wpabuf_free(pix);
+ wpabuf_free(prx);
+ wpabuf_free(bix);
+ wpabuf_free(brx);
+ return res;
+}
+
+
+int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
+{
+ struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
+ const u8 *addr[7];
+ size_t len[7];
+ size_t i, num_elem = 0;
+ size_t nonce_len;
+ u8 one = 1;
+ int res = -1;
+
+ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
+ nonce_len = auth->curve->nonce_len;
+
+ if (auth->initiator) {
+ pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ if (auth->own_bi)
+ bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ else
+ bix = NULL;
+ if (!auth->peer_bi)
+ goto fail;
+ brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ } else {
+ pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (auth->peer_bi)
+ bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ else
+ bix = NULL;
+ if (!auth->own_bi)
+ goto fail;
+ brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ }
+ if (!pix || !prx || !brx)
+ goto fail;
+
+ addr[num_elem] = auth->r_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = auth->i_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(prx);
+ len[num_elem] = wpabuf_len(prx) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(pix);
+ len[num_elem] = wpabuf_len(pix) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(brx);
+ len[num_elem] = wpabuf_len(brx) / 2;
+ num_elem++;
+
+ if (bix) {
+ addr[num_elem] = wpabuf_head(bix);
+ len[num_elem] = wpabuf_len(bix) / 2;
+ num_elem++;
+ }
+
+ addr[num_elem] = &one;
+ len[num_elem] = 1;
+ num_elem++;
+
+ wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
+ res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
+ if (res == 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
+ auth->curve->hash_len);
+fail:
+ wpabuf_free(pix);
+ wpabuf_free(prx);
+ wpabuf_free(bix);
+ wpabuf_free(brx);
+ return res;
+}
+
+
+int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
+{
+ const EC_GROUP *group;
+ EC_POINT *l = NULL;
+ const EC_KEY *BI, *bR, *pR;
+ const EC_POINT *BI_point;
+ BN_CTX *bnctx;
+ BIGNUM *lx, *sum, *q;
+ const BIGNUM *bR_bn, *pR_bn;
+ int ret = -1;
+
+ /* L = ((bR + pR) modulo q) * BI */
+
+ bnctx = BN_CTX_new();
+ sum = BN_new();
+ q = BN_new();
+ lx = BN_new();
+ if (!bnctx || !sum || !q || !lx)
+ goto fail;
+ BI = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
+ if (!BI)
+ goto fail;
+ BI_point = EC_KEY_get0_public_key(BI);
+ group = EC_KEY_get0_group(BI);
+ if (!group)
+ goto fail;
+
+ bR = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
+ pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
+ if (!bR || !pR)
+ goto fail;
+ bR_bn = EC_KEY_get0_private_key(bR);
+ pR_bn = EC_KEY_get0_private_key(pR);
+ if (!bR_bn || !pR_bn)
+ goto fail;
+ if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
+ BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
+ goto fail;
+ l = EC_POINT_new(group);
+ if (!l ||
+ EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
+ bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
+ ret = 0;
+fail:
+ EC_POINT_clear_free(l);
+ BN_clear_free(lx);
+ BN_clear_free(sum);
+ BN_free(q);
+ BN_CTX_free(bnctx);
+ return ret;
+}
+
+
+int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
+{
+ const EC_GROUP *group;
+ EC_POINT *l = NULL, *sum = NULL;
+ const EC_KEY *bI, *BR, *PR;
+ const EC_POINT *BR_point, *PR_point;
+ BN_CTX *bnctx;
+ BIGNUM *lx;
+ const BIGNUM *bI_bn;
+ int ret = -1;
+
+ /* L = bI * (BR + PR) */
+
+ bnctx = BN_CTX_new();
+ lx = BN_new();
+ if (!bnctx || !lx)
+ goto fail;
+ BR = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
+ PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
+ if (!BR || !PR)
+ goto fail;
+ BR_point = EC_KEY_get0_public_key(BR);
+ PR_point = EC_KEY_get0_public_key(PR);
+
+ bI = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
+ if (!bI)
+ goto fail;
+ group = EC_KEY_get0_group(bI);
+ bI_bn = EC_KEY_get0_private_key(bI);
+ if (!group || !bI_bn)
+ goto fail;
+ sum = EC_POINT_new(group);
+ l = EC_POINT_new(group);
+ if (!sum || !l ||
+ EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
+ EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
+ bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
+ ret = 0;
+fail:
+ EC_POINT_clear_free(l);
+ EC_POINT_clear_free(sum);
+ BN_clear_free(lx);
+ BN_CTX_free(bnctx);
+ return ret;
+}
+
+
+int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "DPP PMK";
+ int res;
+
+ /* PMK = HKDF(<>, "DPP PMK", N.x) */
+
+ /* HKDF-Extract(<>, N.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
+ pmk, hash_len);
+ return 0;
+}
+
+
+int dpp_derive_pmkid(const struct dpp_curve_params *curve,
+ EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
+{
+ struct wpabuf *nkx, *pkx;
+ int ret = -1, res;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 hash[SHA256_MAC_LEN];
+
+ /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
+ nkx = dpp_get_pubkey_point(own_key, 0);
+ pkx = dpp_get_pubkey_point(peer_key, 0);
+ if (!nkx || !pkx)
+ goto fail;
+ addr[0] = wpabuf_head(nkx);
+ len[0] = wpabuf_len(nkx) / 2;
+ addr[1] = wpabuf_head(pkx);
+ len[1] = wpabuf_len(pkx) / 2;
+ if (len[0] != len[1])
+ goto fail;
+ if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
+ addr[0] = wpabuf_head(pkx);
+ addr[1] = wpabuf_head(nkx);
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
+ res = sha256_vector(2, addr, len, hash);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
+ ret = 0;
+fail:
+ wpabuf_free(nkx);
+ wpabuf_free(pkx);
+ return ret;
+}
+
+
+/* Role-specific elements for PKEX */
+
+/* NIST P-256 */
+static const u8 pkex_init_x_p256[32] = {
+ 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
+ 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
+ 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
+ 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
+ };
+static const u8 pkex_init_y_p256[32] = {
+ 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
+ 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
+ 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
+ 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
+ };
+static const u8 pkex_resp_x_p256[32] = {
+ 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
+ 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
+ 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
+ 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
+};
+static const u8 pkex_resp_y_p256[32] = {
+ 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
+ 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
+ 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
+ 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
+};
+
+/* NIST P-384 */
+static const u8 pkex_init_x_p384[48] = {
+ 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
+ 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
+ 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
+ 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
+ 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
+ 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
+};
+static const u8 pkex_init_y_p384[48] = {
+ 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
+ 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
+ 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
+ 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
+ 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
+ 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
+};
+static const u8 pkex_resp_x_p384[48] = {
+ 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
+ 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
+ 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
+ 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
+ 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
+ 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
+};
+static const u8 pkex_resp_y_p384[48] = {
+ 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
+ 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
+ 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
+ 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
+ 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
+ 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
+};
+
+/* NIST P-521 */
+static const u8 pkex_init_x_p521[66] = {
+ 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
+ 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
+ 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
+ 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
+ 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
+ 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
+ 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
+ 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
+ 0x97, 0x76
+};
+static const u8 pkex_init_y_p521[66] = {
+ 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
+ 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
+ 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
+ 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
+ 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
+ 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
+ 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
+ 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
+ 0x03, 0xa8
+};
+static const u8 pkex_resp_x_p521[66] = {
+ 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
+ 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
+ 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
+ 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
+ 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
+ 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
+ 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
+ 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
+ 0x84, 0xb4
+};
+static const u8 pkex_resp_y_p521[66] = {
+ 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
+ 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
+ 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
+ 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
+ 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
+ 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
+ 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
+ 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
+ 0xce, 0xe1
+};
+
+/* Brainpool P-256r1 */
+static const u8 pkex_init_x_bp_p256r1[32] = {
+ 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
+ 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
+ 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
+ 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
+};
+static const u8 pkex_init_y_bp_p256r1[32] = {
+ 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
+ 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
+ 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
+ 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
+};
+static const u8 pkex_resp_x_bp_p256r1[32] = {
+ 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
+ 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
+ 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
+ 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
+};
+static const u8 pkex_resp_y_bp_p256r1[32] = {
+ 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
+ 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
+ 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
+ 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
+};
+
+/* Brainpool P-384r1 */
+static const u8 pkex_init_x_bp_p384r1[48] = {
+ 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
+ 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
+ 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
+ 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
+ 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
+ 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
+};
+static const u8 pkex_init_y_bp_p384r1[48] = {
+ 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
+ 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
+ 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
+ 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
+ 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
+ 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
+};
+static const u8 pkex_resp_x_bp_p384r1[48] = {
+ 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
+ 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
+ 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
+ 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
+ 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
+ 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
+};
+static const u8 pkex_resp_y_bp_p384r1[48] = {
+ 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
+ 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
+ 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
+ 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
+ 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
+ 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
+};
+
+/* Brainpool P-512r1 */
+static const u8 pkex_init_x_bp_p512r1[64] = {
+ 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
+ 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
+ 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
+ 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
+ 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
+ 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
+ 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
+ 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
+};
+static const u8 pkex_init_y_bp_p512r1[64] = {
+ 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
+ 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
+ 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
+ 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
+ 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
+ 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
+ 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
+ 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
+};
+static const u8 pkex_resp_x_bp_p512r1[64] = {
+ 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
+ 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
+ 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
+ 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
+ 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
+ 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
+ 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
+ 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
+};
+static const u8 pkex_resp_y_bp_p512r1[64] = {
+ 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
+ 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
+ 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
+ 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
+ 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
+ 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
+ 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
+ 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
+};
+
+
+static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
+ int init)
+{
+ EC_GROUP *group;
+ size_t len = curve->prime_len;
+ const u8 *x, *y;
+ EVP_PKEY *res;
+
+ switch (curve->ike_group) {
+ case 19:
+ x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
+ y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
+ break;
+ case 20:
+ x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
+ y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
+ break;
+ case 21:
+ x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
+ y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
+ break;
+ case 28:
+ x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
+ y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
+ break;
+ case 29:
+ x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
+ y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
+ break;
+ case 30:
+ x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
+ y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
+ break;
+ default:
+ return NULL;
+ }
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group)
+ return NULL;
+ res = dpp_set_pubkey_point_group(group, x, y, len);
+ EC_GROUP_free(group);
+ return res;
+}
+
+
+EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
+ const u8 *mac_init, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ EC_GROUP **ret_group)
+{
+ u8 hash[DPP_MAX_HASH_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ unsigned int num_elem = 0;
+ EC_POINT *Qi = NULL;
+ EVP_PKEY *Pi = NULL;
+ const EC_KEY *Pi_ec;
+ const EC_POINT *Pi_point;
+ BIGNUM *hash_bn = NULL;
+ const EC_GROUP *group = NULL;
+ EC_GROUP *group2 = NULL;
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+
+ wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
+ addr[num_elem] = mac_init;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ addr[num_elem] = (const u8 *) code;
+ len[num_elem] = os_strlen(code);
+ num_elem++;
+ if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: H(MAC-Initiator | [identifier |] code)",
+ hash, curve->hash_len);
+ Pi = dpp_pkex_get_role_elem(curve, 1);
+ if (!Pi)
+ goto fail;
+ dpp_debug_print_key("DPP: Pi", Pi);
+ Pi_ec = EVP_PKEY_get0_EC_KEY(Pi);
+ if (!Pi_ec)
+ goto fail;
+ Pi_point = EC_KEY_get0_public_key(Pi_ec);
+
+ group = EC_KEY_get0_group(Pi_ec);
+ if (!group)
+ goto fail;
+ group2 = EC_GROUP_dup(group);
+ if (!group2)
+ goto fail;
+ Qi = EC_POINT_new(group2);
+ if (!Qi) {
+ EC_GROUP_free(group2);
+ goto fail;
+ }
+ hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
+ if (!hash_bn ||
+ EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
+ goto fail;
+ if (EC_POINT_is_at_infinity(group, Qi)) {
+ wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: Qi", group, Qi);
+out:
+ EVP_PKEY_free(Pi);
+ BN_clear_free(hash_bn);
+ if (ret_group && Qi)
+ *ret_group = group2;
+ else
+ EC_GROUP_free(group2);
+ return Qi;
+fail:
+ EC_POINT_free(Qi);
+ Qi = NULL;
+ goto out;
+}
+
+
+EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
+ const u8 *mac_resp, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ EC_GROUP **ret_group)
+{
+ u8 hash[DPP_MAX_HASH_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ unsigned int num_elem = 0;
+ EC_POINT *Qr = NULL;
+ EVP_PKEY *Pr = NULL;
+ const EC_KEY *Pr_ec;
+ const EC_POINT *Pr_point;
+ BIGNUM *hash_bn = NULL;
+ const EC_GROUP *group = NULL;
+ EC_GROUP *group2 = NULL;
+
+ /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+
+ wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
+ addr[num_elem] = mac_resp;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ addr[num_elem] = (const u8 *) code;
+ len[num_elem] = os_strlen(code);
+ num_elem++;
+ if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: H(MAC-Responder | [identifier |] code)",
+ hash, curve->hash_len);
+ Pr = dpp_pkex_get_role_elem(curve, 0);
+ if (!Pr)
+ goto fail;
+ dpp_debug_print_key("DPP: Pr", Pr);
+ Pr_ec = EVP_PKEY_get0_EC_KEY(Pr);
+ if (!Pr_ec)
+ goto fail;
+ Pr_point = EC_KEY_get0_public_key(Pr_ec);
+
+ group = EC_KEY_get0_group(Pr_ec);
+ if (!group)
+ goto fail;
+ group2 = EC_GROUP_dup(group);
+ if (!group2)
+ goto fail;
+ Qr = EC_POINT_new(group2);
+ if (!Qr) {
+ EC_GROUP_free(group2);
+ goto fail;
+ }
+ hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
+ if (!hash_bn ||
+ EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
+ goto fail;
+ if (EC_POINT_is_at_infinity(group, Qr)) {
+ wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: Qr", group, Qr);
+out:
+ EVP_PKEY_free(Pr);
+ BN_clear_free(hash_bn);
+ if (ret_group && Qr)
+ *ret_group = group2;
+ else
+ EC_GROUP_free(group2);
+ return Qr;
+fail:
+ EC_POINT_free(Qr);
+ Qr = NULL;
+ goto out;
+}
+
+
+int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+ const u8 *Mx, size_t Mx_len,
+ const u8 *Nx, size_t Nx_len,
+ const char *code,
+ const u8 *Kx, size_t Kx_len,
+ u8 *z, unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ int res;
+ u8 *info, *pos;
+ size_t info_len;
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+
+ /* HKDF-Extract(<>, IKM=K.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
+ prk, hash_len);
+ info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
+ info = os_malloc(info_len);
+ if (!info)
+ return -1;
+ pos = info;
+ os_memcpy(pos, mac_init, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, mac_resp, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, Mx, Mx_len);
+ pos += Mx_len;
+ os_memcpy(pos, Nx, Nx_len);
+ pos += Nx_len;
+ os_memcpy(pos, code, os_strlen(code));
+
+ /* HKDF-Expand(PRK, info, L) */
+ if (hash_len == 32)
+ res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else if (hash_len == 48)
+ res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else if (hash_len == 64)
+ res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else
+ res = -1;
+ os_free(info);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
+ z, hash_len);
+ return 0;
+}
+
+
+int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct json_token *peer_net_access_key)
+{
+ BN_CTX *bnctx = NULL;
+ EVP_PKEY *own_key = NULL, *peer_key = NULL;
+ BIGNUM *sum = NULL, *q = NULL, *mx = NULL;
+ EC_POINT *m = NULL;
+ const EC_KEY *cR, *pR;
+ const EC_GROUP *group;
+ const BIGNUM *cR_bn, *pR_bn;
+ const EC_POINT *CI_point;
+ const EC_KEY *CI;
+ u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 prk[DPP_MAX_HASH_LEN];
+ const struct dpp_curve_params *curve;
+ int res = -1;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
+
+ own_key = dpp_set_keypair(&auth->curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ dpp_auth_fail(auth, "Failed to parse own netAccessKey");
+ goto fail;
+ }
+
+ peer_key = dpp_parse_jwk(peer_net_access_key, &curve);
+ if (!peer_key)
+ goto fail;
+ dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
+
+ if (auth->curve != curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
+ auth->curve->name, curve->name);
+ goto fail;
+ }
+
+ auth->own_protocol_key = dpp_gen_keypair(curve);
+ if (!auth->own_protocol_key)
+ goto fail;
+
+ if (random_get_bytes(auth->e_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: E-nonce",
+ auth->e_nonce, auth->curve->nonce_len);
+
+ /* M = { cR + pR } * CI */
+ cR = EVP_PKEY_get0_EC_KEY(own_key);
+ pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
+ if (!pR)
+ goto fail;
+ group = EC_KEY_get0_group(pR);
+ bnctx = BN_CTX_new();
+ sum = BN_new();
+ mx = BN_new();
+ q = BN_new();
+ m = EC_POINT_new(group);
+ if (!cR || !bnctx || !sum || !mx || !q || !m)
+ goto fail;
+ cR_bn = EC_KEY_get0_private_key(cR);
+ pR_bn = EC_KEY_get0_private_key(pR);
+ if (!cR_bn || !pR_bn)
+ goto fail;
+ CI = EVP_PKEY_get0_EC_KEY(peer_key);
+ CI_point = EC_KEY_get0_public_key(CI);
+ if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
+ BN_mod_add(sum, cR_bn, pR_bn, q, bnctx) != 1 ||
+ EC_POINT_mul(group, m, NULL, CI_point, sum, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
+ bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
+
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
+
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
+ Mx, curve->prime_len, prk) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
+
+ /* HKDF-Expand(PRK, "dpp reconfig key", L) */
+ if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
+ "dpp reconfig key", auth->ke, curve->hash_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
+ auth->ke, curve->hash_len);
+
+ res = 0;
+ EVP_PKEY_free(auth->reconfig_old_protocol_key);
+ auth->reconfig_old_protocol_key = own_key;
+ own_key = NULL;
+fail:
+ forced_memzero(prk, sizeof(prk));
+ forced_memzero(Mx, sizeof(Mx));
+ EC_POINT_clear_free(m);
+ BN_free(q);
+ BN_clear_free(mx);
+ BN_clear_free(sum);
+ EVP_PKEY_free(own_key);
+ EVP_PKEY_free(peer_key);
+ BN_CTX_free(bnctx);
+ return res;
+}
+
+
+int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
+ const u8 *r_proto, u16 r_proto_len,
+ struct json_token *net_access_key)
+{
+ BN_CTX *bnctx = NULL;
+ EVP_PKEY *pr = NULL, *peer_key = NULL;
+ EC_POINT *sum = NULL, *m = NULL;
+ BIGNUM *mx = NULL;
+ const EC_KEY *cI, *CR, *PR;
+ const EC_GROUP *group;
+ const EC_POINT *CR_point, *PR_point;
+ const BIGNUM *cI_bn;
+ u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 prk[DPP_MAX_HASH_LEN];
+ int res = -1;
+ const struct dpp_curve_params *curve;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
+
+ pr = dpp_set_pubkey_point(auth->conf->connector_key,
+ r_proto, r_proto_len);
+ if (!pr) {
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key");
+ goto fail;
+ }
+ dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
+ EVP_PKEY_free(auth->peer_protocol_key);
+ auth->peer_protocol_key = pr;
+ pr = NULL;
+
+ peer_key = dpp_parse_jwk(net_access_key, &curve);
+ if (!peer_key)
+ goto fail;
+ dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
+ if (auth->curve != curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
+ auth->curve->name, curve->name);
+ goto fail;
+ }
+
+ /* M = cI * { CR + PR } */
+ cI = EVP_PKEY_get0_EC_KEY(auth->conf->connector_key);
+ cI_bn = EC_KEY_get0_private_key(cI);
+ group = EC_KEY_get0_group(cI);
+ bnctx = BN_CTX_new();
+ sum = EC_POINT_new(group);
+ m = EC_POINT_new(group);
+ mx = BN_new();
+ CR = EVP_PKEY_get0_EC_KEY(peer_key);
+ PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
+ CR_point = EC_KEY_get0_public_key(CR);
+ PR_point = EC_KEY_get0_public_key(PR);
+ if (!bnctx || !sum || !m || !mx ||
+ EC_POINT_add(group, sum, CR_point, PR_point, bnctx) != 1 ||
+ EC_POINT_mul(group, m, NULL, sum, cI_bn, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
+ bnctx) != 1 ||
+ dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
+
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
+
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
+ Mx, curve->prime_len, prk) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
+
+ /* HKDF-Expand(PRK, "dpp reconfig key", L) */
+ if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
+ "dpp reconfig key", auth->ke, curve->hash_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
+ auth->ke, curve->hash_len);
+
+ res = 0;
+fail:
+ forced_memzero(prk, sizeof(prk));
+ forced_memzero(Mx, sizeof(Mx));
+ EVP_PKEY_free(pr);
+ EVP_PKEY_free(peer_key);
+ EC_POINT_clear_free(sum);
+ EC_POINT_clear_free(m);
+ BN_clear_free(mx);
+ BN_CTX_free(bnctx);
+ return res;
+}
+
+
+static char *
+dpp_build_jws_prot_hdr(struct dpp_configurator *conf, size_t *signed1_len)
+{
+ struct wpabuf *jws_prot_hdr;
+ char *signed1;
+
+ jws_prot_hdr = wpabuf_alloc(100);
+ if (!jws_prot_hdr)
+ return NULL;
+ json_start_object(jws_prot_hdr, NULL);
+ json_add_string(jws_prot_hdr, "typ", "dppCon");
+ json_value_sep(jws_prot_hdr);
+ json_add_string(jws_prot_hdr, "kid", conf->kid);
+ json_value_sep(jws_prot_hdr);
+ json_add_string(jws_prot_hdr, "alg", conf->curve->jws_alg);
+ json_end_object(jws_prot_hdr);
+ signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
+ wpabuf_len(jws_prot_hdr),
+ signed1_len);
+ wpabuf_free(jws_prot_hdr);
+ return signed1;
+}
+
+
+static char *
+dpp_build_conn_signature(struct dpp_configurator *conf,
+ const char *signed1, size_t signed1_len,
+ const char *signed2, size_t signed2_len,
+ size_t *signed3_len)
+{
+ const struct dpp_curve_params *curve;
+ char *signed3 = NULL;
+ unsigned char *signature = NULL;
+ const unsigned char *p;
+ size_t signature_len;
+ EVP_MD_CTX *md_ctx = NULL;
+ ECDSA_SIG *sig = NULL;
+ char *dot = ".";
+ const EVP_MD *sign_md;
+ const BIGNUM *r, *s;
+
+ curve = conf->curve;
+ if (curve->hash_len == SHA256_MAC_LEN) {
+ sign_md = EVP_sha256();
+ } else if (curve->hash_len == SHA384_MAC_LEN) {
+ sign_md = EVP_sha384();
+ } else if (curve->hash_len == SHA512_MAC_LEN) {
+ sign_md = EVP_sha512();
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
+ goto fail;
+ }
+
+ md_ctx = EVP_MD_CTX_create();
+ if (!md_ctx)
+ goto fail;
+
+ ERR_clear_error();
+ if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, conf->csign) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
+ EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
+ EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ signature = os_malloc(signature_len);
+ if (!signature)
+ goto fail;
+ if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
+ signature, signature_len);
+ /* Convert to raw coordinates r,s */
+ p = signature;
+ sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
+ if (!sig)
+ goto fail;
+ ECDSA_SIG_get0(sig, &r, &s);
+ if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(s, signature + curve->prime_len,
+ curve->prime_len) < 0)
+ goto fail;
+ signature_len = 2 * curve->prime_len;
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
+ signature, signature_len);
+ signed3 = base64_url_encode(signature, signature_len, signed3_len);
+fail:
+ EVP_MD_CTX_destroy(md_ctx);
+ ECDSA_SIG_free(sig);
+ os_free(signature);
+ return signed3;
+}
+
+char * dpp_sign_connector(struct dpp_configurator *conf,
+ const struct wpabuf *dppcon)
+{
+ char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
+ char *signed_conn = NULL, *pos;
+ size_t signed1_len, signed2_len, signed3_len;
+
+ signed1 = dpp_build_jws_prot_hdr(conf, &signed1_len);
+ signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
+ &signed2_len);
+ if (!signed1 || !signed2)
+ goto fail;
+
+ signed3 = dpp_build_conn_signature(conf, signed1, signed1_len,
+ signed2, signed2_len, &signed3_len);
+ if (!signed3)
+ goto fail;
+
+ signed_conn = os_malloc(signed1_len + signed2_len + signed3_len + 3);
+ if (!signed_conn)
+ goto fail;
+ pos = signed_conn;
+ os_memcpy(pos, signed1, signed1_len);
+ pos += signed1_len;
+ *pos++ = '.';
+ os_memcpy(pos, signed2, signed2_len);
+ pos += signed2_len;
+ *pos++ = '.';
+ os_memcpy(pos, signed3, signed3_len);
+ pos += signed3_len;
+ *pos = '\0';
+
+fail:
+ os_free(signed1);
+ os_free(signed2);
+ os_free(signed3);
+ return signed_conn;
+}
+
+
+#ifdef CONFIG_DPP2
+
+struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
+ size_t net_access_key_len)
+{
+ struct wpabuf *pub = NULL;
+ EVP_PKEY *own_key;
+ struct dpp_pfs *pfs;
+
+ pfs = os_zalloc(sizeof(*pfs));
+ if (!pfs)
+ return NULL;
+
+ own_key = dpp_set_keypair(&pfs->curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+ EVP_PKEY_free(own_key);
+
+ pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
+ if (!pfs->ecdh)
+ goto fail;
+
+ pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
+ pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
+ if (!pub)
+ goto fail;
+
+ pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
+ if (!pfs->ie)
+ goto fail;
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
+ wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
+ wpabuf_put_buf(pfs->ie, pub);
+ wpabuf_free(pub);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
+ pfs->ie);
+
+ return pfs;
+fail:
+ wpabuf_free(pub);
+ dpp_pfs_free(pfs);
+ return NULL;
+}
+
+
+int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
+{
+ if (peer_ie_len < 2)
+ return -1;
+ if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
+ return -1;
+ }
+
+ pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
+ peer_ie_len - 2);
+ pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
+ if (!pfs->secret) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
+ return -1;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
+ return 0;
+}
+
+
+void dpp_pfs_free(struct dpp_pfs *pfs)
+{
+ if (!pfs)
+ return;
+ crypto_ecdh_deinit(pfs->ecdh);
+ wpabuf_free(pfs->ie);
+ wpabuf_clear_free(pfs->secret);
+ os_free(pfs);
+}
+
+
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
+{
+ X509_REQ *req = NULL;
+ struct wpabuf *buf = NULL;
+ unsigned char *der;
+ int der_len;
+ EVP_PKEY *key;
+ const EVP_MD *sign_md;
+ unsigned int hash_len = auth->curve->hash_len;
+ EC_KEY *eckey;
+ BIO *out = NULL;
+ u8 cp[DPP_CP_LEN];
+ char *password;
+ size_t password_len;
+ int res;
+
+ /* TODO: use auth->csrattrs */
+
+ /* TODO: support generation of a new private key if csrAttrs requests
+ * a specific group to be used */
+ key = auth->own_protocol_key;
+
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!eckey)
+ goto fail;
+ der = NULL;
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len <= 0)
+ goto fail;
+ wpabuf_free(auth->priv_key);
+ auth->priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!auth->priv_key)
+ goto fail;
+
+ req = X509_REQ_new();
+ if (!req || !X509_REQ_set_pubkey(req, key))
+ goto fail;
+
+ if (name) {
+ X509_NAME *n;
+
+ n = X509_REQ_get_subject_name(req);
+ if (!n)
+ goto fail;
+
+ if (X509_NAME_add_entry_by_txt(
+ n, "CN", MBSTRING_UTF8,
+ (const unsigned char *) name, -1, -1, 0) != 1)
+ goto fail;
+ }
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ cp, DPP_CP_LEN);
+ password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
+ forced_memzero(cp, DPP_CP_LEN);
+ if (!password)
+ goto fail;
+
+ res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
+ V_ASN1_UTF8STRING,
+ (const unsigned char *) password,
+ password_len);
+ bin_clear_free(password, password_len);
+ if (!res)
+ goto fail;
+
+ /* TODO */
+
+ /* TODO: hash func selection based on csrAttrs */
+ if (hash_len == SHA256_MAC_LEN) {
+ sign_md = EVP_sha256();
+ } else if (hash_len == SHA384_MAC_LEN) {
+ sign_md = EVP_sha384();
+ } else if (hash_len == SHA512_MAC_LEN) {
+ sign_md = EVP_sha512();
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
+ goto fail;
+ }
+
+ if (!X509_REQ_sign(req, key, sign_md))
+ goto fail;
+
+ der = NULL;
+ der_len = i2d_X509_REQ(req, &der);
+ if (der_len < 0)
+ goto fail;
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
+
+fail:
+ BIO_free_all(out);
+ X509_REQ_free(req);
+ return buf;
+}
+
+
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7)
+{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7 *p7 = NULL;
+ const unsigned char *p = wpabuf_head(pkcs7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ STACK_OF(X509) *certs;
+ int i, num;
+ BIO *out = NULL;
+ size_t rlen;
+ struct wpabuf *pem = NULL;
+ int res;
+
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
+ if (!p7) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ switch (OBJ_obj2nid(p7->type)) {
+ case NID_pkcs7_signed:
+ certs = p7->d.sign->cert;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ certs = p7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ break;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (!certs || ((num = sk_X509_num(certs)) == 0)) {
+ wpa_printf(MSG_INFO,
+ "DPP: No certificates found in PKCS#7 object");
+ goto fail;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ goto fail;
+
+ for (i = 0; i < num; i++) {
+ X509 *cert = sk_X509_value(certs, i);
+
+ PEM_write_bio_X509(out, cert);
+ }
+
+ rlen = BIO_ctrl_pending(out);
+ pem = wpabuf_alloc(rlen);
+ if (!pem)
+ goto fail;
+ res = BIO_read(out, wpabuf_put(pem, 0), rlen);
+ if (res <= 0) {
+ wpabuf_free(pem);
+ pem = NULL;
+ goto fail;
+ }
+ wpabuf_put(pem, res);
+
+fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ if (out)
+ BIO_free_all(out);
+
+ return pem;
+}
+
+
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
+{
+ X509_REQ *req;
+ const unsigned char *pos;
+ EVP_PKEY *pkey;
+ int res, loc, ret = -1;
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *type;
+ ASN1_STRING *str;
+ unsigned char *utf8 = NULL;
+ unsigned char *cp = NULL;
+ size_t cp_len;
+ u8 exp_cp[DPP_CP_LEN];
+ unsigned int hash_len = auth->curve->hash_len;
+
+ pos = wpabuf_head(csr);
+ req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
+ if (!req) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
+ return -1;
+ }
+
+ pkey = X509_REQ_get_pubkey(req);
+ if (!pkey) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
+ goto fail;
+ }
+
+ res = X509_REQ_verify(req, pkey);
+ EVP_PKEY_free(pkey);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not have a valid signature");
+ goto fail;
+ }
+
+ loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
+ if (loc < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not include challengePassword");
+ goto fail;
+ }
+
+ attr = X509_REQ_get_attr(req, loc);
+ if (!attr) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute");
+ goto fail;
+ }
+
+ type = X509_ATTRIBUTE_get0_type(attr, 0);
+ if (!type) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute type");
+ goto fail;
+ }
+
+ res = ASN1_TYPE_get(type);
+ /* This is supposed to be UTF8String, but allow other strings as well
+ * since challengePassword is using ASCII (base64 encoded). */
+ if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
+ res != V_ASN1_IA5STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected challengePassword attribute type %d",
+ res);
+ goto fail;
+ }
+
+ str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
+ if (!str) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get ASN.1 string for challengePassword");
+ goto fail;
+ }
+
+ res = ASN1_STRING_to_UTF8(&utf8, str);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get UTF8 version of challengePassword");
+ goto fail;
+ }
+
+ cp = base64_decode((const char *) utf8, res, &cp_len);
+ OPENSSL_free(utf8);
+ if (!cp) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not base64 decode challengePassword");
+ goto fail;
+ }
+ if (cp_len != DPP_CP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected cp length (%zu) in CSR challengePassword",
+ cp_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: cp from CSR challengePassword",
+ cp, cp_len);
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", exp_cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ exp_cp, DPP_CP_LEN);
+ if (os_memcmp_const(cp, exp_cp, DPP_CP_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR challengePassword does not match calculated cp");
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ os_free(cp);
+ X509_REQ_free(req);
+ return ret;
+}
+
+
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *pp_key,
+ size_t pp_key_len)
+{
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL, *ppkey = NULL;
+ struct dpp_reconfig_id *id = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign)
+ goto fail;
+
+ if (!pp_key)
+ goto fail;
+ p = pp_key;
+ ppkey = d2i_PUBKEY(NULL, &p, pp_key_len);
+ if (!ppkey)
+ goto fail;
+
+ eckey = EVP_PKEY_get0_EC_KEY(csign);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ goto fail;
+
+ e_id = EC_POINT_new(group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ if (!e_id || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(group, q, ctx) ||
+ !BN_rand_range(bn, q) ||
+ !EC_POINT_mul(group, e_id, bn, NULL, NULL, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated random point E-id", group, e_id);
+
+ id = os_zalloc(sizeof(*id));
+ if (!id)
+ goto fail;
+ id->group = group;
+ id->e_id = e_id;
+ e_id = NULL;
+ id->csign = csign;
+ csign = NULL;
+ id->pp_key = ppkey;
+ ppkey = NULL;
+fail:
+ EC_POINT_free(e_id);
+ EVP_PKEY_free(csign);
+ EVP_PKEY_free(ppkey);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return id;
+}
+
+
+static EVP_PKEY * dpp_pkey_from_point(const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ EC_KEY *eckey;
+ EVP_PKEY *pkey = NULL;
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto fail;
+ }
+
+fail:
+ EC_KEY_free(eckey);
+ return pkey;
+}
+
+
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ EC_POINT *e_prime_id = NULL, *a_nonce = NULL;
+ int ret = -1;
+ const EC_KEY *pp;
+ const EC_POINT *pp_point;
+
+ pp = EVP_PKEY_get0_EC_KEY(id->pp_key);
+ if (!pp)
+ goto fail;
+ pp_point = EC_KEY_get0_public_key(pp);
+ e_prime_id = EC_POINT_new(id->group);
+ a_nonce = EC_POINT_new(id->group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ /* Generate random 0 <= a-nonce < q
+ * A-NONCE = a-nonce * G
+ * E'-id = E-id + a-nonce * P_pk */
+ if (!pp_point || !e_prime_id || !a_nonce || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(id->group, q, ctx) ||
+ !BN_rand_range(bn, q) || /* bn = a-nonce */
+ !EC_POINT_mul(id->group, a_nonce, bn, NULL, NULL, ctx) ||
+ !EC_POINT_mul(id->group, e_prime_id, NULL, pp_point, bn, ctx) ||
+ !EC_POINT_add(id->group, e_prime_id, id->e_id, e_prime_id, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated A-NONCE", id->group, a_nonce);
+ dpp_debug_print_point("DPP: Encrypted E-id to E'-id",
+ id->group, e_prime_id);
+
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ id->a_nonce = dpp_pkey_from_point(id->group, a_nonce);
+ id->e_prime_id = dpp_pkey_from_point(id->group, e_prime_id);
+ if (!id->a_nonce || !id->e_prime_id)
+ goto fail;
+
+ ret = 0;
+
+fail:
+ EC_POINT_free(e_prime_id);
+ EC_POINT_free(a_nonce);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
+{
+ if (id) {
+ EC_POINT_clear_free(id->e_id);
+ EVP_PKEY_free(id->csign);
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ EVP_PKEY_free(id->pp_key);
+ os_free(id);
+ }
+}
+
+
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id)
+{
+ const EC_KEY *pp_ec, *a_nonce_ec, *e_prime_id_ec;
+ const BIGNUM *pp_bn;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+ const EC_POINT *a_nonce_point, *e_prime_id_point;
+ BN_CTX *ctx = NULL;
+
+ if (!ppkey)
+ return NULL;
+
+ /* E-id = E'-id - s_C * A-NONCE */
+ pp_ec = EVP_PKEY_get0_EC_KEY(ppkey);
+ a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
+ e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
+ if (!pp_ec || !a_nonce_ec || !e_prime_id_ec)
+ return NULL;
+ pp_bn = EC_KEY_get0_private_key(pp_ec);
+ group = EC_KEY_get0_group(pp_ec);
+ a_nonce_point = EC_KEY_get0_public_key(a_nonce_ec);
+ e_prime_id_point = EC_KEY_get0_public_key(e_prime_id_ec);
+ ctx = BN_CTX_new();
+ if (!pp_bn || !group || !a_nonce_point || !e_prime_id_point || !ctx)
+ goto fail;
+ e_id = EC_POINT_new(group);
+ if (!e_id ||
+ !EC_POINT_mul(group, e_id, NULL, a_nonce_point, pp_bn, ctx) ||
+ !EC_POINT_invert(group, e_id, ctx) ||
+ !EC_POINT_add(group, e_id, e_prime_id_point, e_id, ctx)) {
+ EC_POINT_clear_free(e_id);
+ goto fail;
+ }
+
+ dpp_debug_print_point("DPP: Decrypted E-id", group, e_id);
+
+fail:
+ BN_CTX_free(ctx);
+ return e_id;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve)
+{
+ BN_CTX *ctx;
+ BIGNUM *x, *y;
+ int ret = -1;
+ EC_GROUP *group;
+ EC_POINT *point;
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group)
+ return -1;
+
+ ctx = BN_CTX_new();
+ point = EC_POINT_new(group);
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !point || !x || !y)
+ goto fail;
+
+ if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ /* Generate a random y coordinate that results in a point that is not
+ * on the curve. */
+ for (;;) {
+ if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
+ ctx) != 1) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
+ /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
+ * return an error from EC_POINT_set_affine_coordinates_GFp()
+ * when the point is not on the curve. */
+ break;
+#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
+ goto fail;
+#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx))
+ break;
+ }
+
+ if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ if (ret < 0)
+ wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
+ BN_free(x);
+ BN_free(y);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+ EC_GROUP_free(group);
+
+ return ret;
+}
+
+
+char * dpp_corrupt_connector_signature(const char *connector)
+{
+ char *tmp, *pos, *signed3 = NULL;
+ unsigned char *signature = NULL;
+ size_t signature_len = 0, signed3_len;
+
+ tmp = os_zalloc(os_strlen(connector) + 5);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, connector, os_strlen(connector));
+
+ pos = os_strchr(tmp, '.');
+ if (!pos)
+ goto fail;
+
+ pos = os_strchr(pos + 1, '.');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
+ pos);
+ signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
+ if (!signature || signature_len == 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
+ signature, signature_len);
+ signature[signature_len - 1] ^= 0x01;
+ wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
+ signature, signature_len);
+ signed3 = base64_url_encode(signature, signature_len, &signed3_len);
+ if (!signed3)
+ goto fail;
+ os_memcpy(pos, signed3, signed3_len);
+ pos[signed3_len] = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
+ pos);
+
+out:
+ os_free(signature);
+ os_free(signed3);
+ return tmp;
+fail:
+ os_free(tmp);
+ tmp = NULL;
+ goto out;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/contrib/wpa/src/common/dpp_i.h b/contrib/wpa/src/common/dpp_i.h
new file mode 100644
index 000000000000..af12467a5d92
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_i.h
@@ -0,0 +1,160 @@
+/*
+ * DPP module internal definitions
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DPP_I_H
+#define DPP_I_H
+
+#ifdef CONFIG_DPP
+
+struct dpp_global {
+ void *msg_ctx;
+ struct dl_list bootstrap; /* struct dpp_bootstrap_info */
+ struct dl_list configurator; /* struct dpp_configurator */
+#ifdef CONFIG_DPP2
+ struct dl_list controllers; /* struct dpp_relay_controller */
+ struct dpp_controller *controller;
+ struct dl_list tcp_init; /* struct dpp_connection */
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
+#endif /* CONFIG_DPP2 */
+};
+
+/* dpp.c */
+
+void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status);
+void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash);
+unsigned int dpp_next_id(struct dpp_global *dpp);
+struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
+struct json_token * dpp_parse_own_connector(const char *own_connector);
+int dpp_connector_match_groups(struct json_token *own_root,
+ struct json_token *peer_root, bool reconfig);
+int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
+ const char *kid, const struct dpp_curve_params *curve);
+EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
+ const struct dpp_curve_params **key_curve);
+int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes, u16 num_modes);
+void dpp_auth_fail(struct dpp_authentication *auth, const char *txt);
+int dpp_gen_uri(struct dpp_bootstrap_info *bi);
+void dpp_write_adv_proto(struct wpabuf *buf);
+void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query);
+
+/* dpp_backup.c */
+
+void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key);
+struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth);
+int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+ const u8 *env_data, size_t env_data_len);
+
+/* dpp_crypto.c */
+
+struct dpp_signed_connector_info {
+ unsigned char *payload;
+ size_t payload_len;
+};
+
+enum dpp_status_error
+dpp_process_signed_connector(struct dpp_signed_connector_info *info,
+ EVP_PKEY *csign_pub, const char *connector);
+enum dpp_status_error
+dpp_check_signed_connector(struct dpp_signed_connector_info *info,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len);
+const struct dpp_curve_params * dpp_get_curve_name(const char *name);
+const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
+const struct dpp_curve_params * dpp_get_curve_nid(int nid);
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
+int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len);
+struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
+EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
+ const u8 *buf_x, const u8 *buf_y,
+ size_t len);
+EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len);
+int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len);
+int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
+ const char *label, u8 *out, size_t outlen);
+int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len);
+void dpp_debug_print_point(const char *title, const EC_GROUP *group,
+ const EC_POINT *point);
+void dpp_debug_print_key(const char *title, EVP_PKEY *key);
+int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len, unsigned int iterations,
+ u8 *buf, size_t buflen);
+int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len);
+int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
+int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len);
+EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len);
+EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve);
+int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
+int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
+int dpp_derive_bk_ke(struct dpp_authentication *auth);
+int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth);
+int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth);
+int dpp_auth_derive_l_responder(struct dpp_authentication *auth);
+int dpp_auth_derive_l_initiator(struct dpp_authentication *auth);
+int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len);
+int dpp_derive_pmkid(const struct dpp_curve_params *curve,
+ EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid);
+EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
+ const u8 *mac_init, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ EC_GROUP **ret_group);
+EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
+ const u8 *mac_resp, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ EC_GROUP **ret_group);
+int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+ const u8 *Mx, size_t Mx_len,
+ const u8 *Nx, size_t Nx_len,
+ const char *code,
+ const u8 *Kx, size_t Kx_len,
+ u8 *z, unsigned int hash_len);
+int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct json_token *peer_net_access_key);
+int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
+ const u8 *r_proto, u16 r_proto_len,
+ struct json_token *net_access_key);
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id);
+char * dpp_sign_connector(struct dpp_configurator *conf,
+ const struct wpabuf *dppcon);
+int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve);
+
+struct dpp_reconfig_id {
+ const EC_GROUP *group;
+ EC_POINT *e_id; /* E-id */
+ EVP_PKEY *csign;
+ EVP_PKEY *a_nonce; /* A-NONCE */
+ EVP_PKEY *e_prime_id; /* E'-id */
+ EVP_PKEY *pp_key;
+};
+
+/* dpp_tcp.c */
+
+void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+void dpp_tcp_init_flush(struct dpp_global *dpp);
+void dpp_relay_flush_controllers(struct dpp_global *dpp);
+
+#endif /* CONFIG_DPP */
+#endif /* DPP_I_H */
diff --git a/contrib/wpa/src/common/dpp_pkex.c b/contrib/wpa/src/common/dpp_pkex.c
new file mode 100644
index 000000000000..807ab7d0a1ce
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_pkex.c
@@ -0,0 +1,1324 @@
+/*
+ * DPP PKEX functionality
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "crypto/crypto.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_ephemeral_key_override[600];
+size_t dpp_pkex_ephemeral_key_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
+#endif
+
+
+static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
+{
+ const EC_KEY *X_ec;
+ const EC_POINT *X_point;
+ BN_CTX *bnctx = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *Qi = NULL, *M = NULL;
+ struct wpabuf *M_buf = NULL;
+ BIGNUM *Mx = NULL, *My = NULL;
+ struct wpabuf *msg = NULL;
+ size_t attr_len;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
+ pkex->identifier, bnctx, &group);
+ if (!Qi)
+ goto fail;
+
+ /* Generate a random ephemeral keypair x/X */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key x/X");
+ pkex->x = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->x = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ pkex->x = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!pkex->x)
+ goto fail;
+
+ /* M = X + Qi */
+ X_ec = EVP_PKEY_get0_EC_KEY(pkex->x);
+ if (!X_ec)
+ goto fail;
+ X_point = EC_KEY_get0_public_key(X_ec);
+ if (!X_point)
+ goto fail;
+ dpp_debug_print_point("DPP: X", group, X_point);
+ M = EC_POINT_new(group);
+ Mx = BN_new();
+ My = BN_new();
+ if (!M || !Mx || !My ||
+ EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
+ goto fail;
+ dpp_debug_print_point("DPP: M", group, M);
+
+ /* Initiator -> Responder: group, [identifier,] M */
+ attr_len = 4 + 2;
+ if (pkex->identifier)
+ attr_len += 4 + os_strlen(pkex->identifier);
+ attr_len += 4 + 2 * curve->prime_len;
+ msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
+ if (!msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
+ goto skip_finite_cyclic_group;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Finite Cyclic Group attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, curve->ike_group);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_finite_cyclic_group:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Code Identifier attribute */
+ if (pkex->identifier) {
+ wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
+ wpabuf_put_le16(msg, os_strlen(pkex->identifier));
+ wpabuf_put_str(msg, pkex->identifier);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* M in Encrypted Key attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
+ wpabuf_put_le16(msg, 2 * curve->prime_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+out:
+ wpabuf_free(M_buf);
+ EC_POINT_free(M);
+ EC_POINT_free(Qi);
+ BN_clear_free(Mx);
+ BN_clear_free(My);
+ BN_CTX_free(bnctx);
+ EC_GROUP_free(group);
+ return msg;
+fail:
+ wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
+{
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const char *identifier,
+ const char *code)
+{
+ struct dpp_pkex *pkex;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ return NULL;
+ pkex->msg_ctx = msg_ctx;
+ pkex->initiator = 1;
+ pkex->own_bi = bi;
+ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+ goto fail;
+ }
+ pkex->code = os_strdup(code);
+ if (!pkex->code)
+ goto fail;
+ pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
+ if (!pkex->exchange_req)
+ goto fail;
+ return pkex;
+fail:
+ dpp_pkex_free(pkex);
+ return NULL;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
+ enum dpp_status_error status,
+ const BIGNUM *Nx, const BIGNUM *Ny)
+{
+ struct wpabuf *msg = NULL;
+ size_t attr_len;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+
+ /* Initiator -> Responder: DPP Status, [identifier,] N */
+ attr_len = 4 + 1;
+ if (pkex->identifier)
+ attr_len += 4 + os_strlen(pkex->identifier);
+ attr_len += 4 + 2 * curve->prime_len;
+ msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
+ if (!msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ }
+
+ if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 255;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Code Identifier attribute */
+ if (pkex->identifier) {
+ wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
+ wpabuf_put_le16(msg, os_strlen(pkex->identifier));
+ wpabuf_put_str(msg, pkex->identifier);
+ }
+
+ if (status != DPP_STATUS_OK)
+ goto skip_encrypted_key;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* N in Encrypted Key attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
+ wpabuf_put_le16(msg, 2 * curve->prime_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+skip_encrypted_key:
+ if (status == DPP_STATUS_BAD_GROUP) {
+ /* Finite Cyclic Group attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, curve->ike_group);
+ }
+
+ return msg;
+fail:
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
+ const char *identifier)
+{
+ if (!attr_id && identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code identifier received, but expected one");
+ return 0;
+ }
+
+ if (attr_id && !identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX code identifier received, but not expecting one");
+ return 0;
+ }
+
+ if (attr_id && identifier &&
+ (os_strlen(identifier) != attr_id_len ||
+ os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
+ wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const u8 *peer_mac,
+ const char *identifier,
+ const char *code,
+ const u8 *buf, size_t len)
+{
+ const u8 *attr_group, *attr_id, *attr_key;
+ u16 attr_group_len, attr_id_len, attr_key_len;
+ const struct dpp_curve_params *curve = bi->curve;
+ u16 ike_group;
+ struct dpp_pkex *pkex = NULL;
+ EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
+ BN_CTX *bnctx = NULL;
+ EC_GROUP *group = NULL;
+ BIGNUM *Mx = NULL, *My = NULL;
+ const EC_KEY *Y_ec;
+ EC_KEY *X_ec = NULL;
+ const EC_POINT *Y_point;
+ BIGNUM *Nx = NULL, *Ny = NULL;
+ u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Kx_len;
+ int res;
+
+ if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "PKEX counter t limit reached - ignore message");
+ return NULL;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_id_len = 0;
+ attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
+ &attr_id_len);
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
+ return NULL;
+
+ attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (!attr_group || attr_group_len != 2) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid Finite Cyclic Group attribute");
+ return NULL;
+ }
+ ike_group = WPA_GET_LE16(attr_group);
+ if (ike_group != curve->ike_group) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Mismatching PKEX curve: peer=%u own=%u",
+ ike_group, curve->ike_group);
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->own_bi = bi;
+ pkex->failed = 1;
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(
+ pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
+ if (!pkex->exchange_resp)
+ goto fail;
+ return pkex;
+ }
+
+ /* M in Encrypted Key attribute */
+ attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
+ attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing Encrypted Key attribute");
+ return NULL;
+ }
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
+ &group);
+ if (!Qi)
+ goto fail;
+
+ /* X' = M - Qi */
+ X = EC_POINT_new(group);
+ M = EC_POINT_new(group);
+ Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+ My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+ if (!X || !M || !Mx || !My ||
+ EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, M) ||
+ !EC_POINT_is_on_curve(group, M, bnctx) ||
+ EC_POINT_invert(group, Qi, bnctx) != 1 ||
+ EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, X) ||
+ !EC_POINT_is_on_curve(group, X, bnctx)) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Invalid Encrypted Key value");
+ bi->pkex_t++;
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: M", group, M);
+ dpp_debug_print_point("DPP: X'", group, X);
+
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->t = bi->pkex_t;
+ pkex->msg_ctx = msg_ctx;
+ pkex->own_bi = bi;
+ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+ goto fail;
+ }
+ pkex->code = os_strdup(code);
+ if (!pkex->code)
+ goto fail;
+
+ os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
+
+ X_ec = EC_KEY_new();
+ if (!X_ec ||
+ EC_KEY_set_group(X_ec, group) != 1 ||
+ EC_KEY_set_public_key(X_ec, X) != 1)
+ goto fail;
+ pkex->x = EVP_PKEY_new();
+ if (!pkex->x ||
+ EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
+ goto fail;
+
+ /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+ Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
+ if (!Qr)
+ goto fail;
+
+ /* Generate a random ephemeral keypair y/Y */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key y/Y");
+ pkex->y = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->y = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ pkex->y = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!pkex->y)
+ goto fail;
+
+ /* N = Y + Qr */
+ Y_ec = EVP_PKEY_get0_EC_KEY(pkex->y);
+ if (!Y_ec)
+ goto fail;
+ Y_point = EC_KEY_get0_public_key(Y_ec);
+ if (!Y_point)
+ goto fail;
+ dpp_debug_print_point("DPP: Y", group, Y_point);
+ N = EC_POINT_new(group);
+ Nx = BN_new();
+ Ny = BN_new();
+ if (!N || !Nx || !Ny ||
+ EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
+ goto fail;
+ dpp_debug_print_point("DPP: N", group, N);
+
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
+ Nx, Ny);
+ if (!pkex->exchange_resp)
+ goto fail;
+
+ /* K = y * X' */
+ if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+ Kx, Kx_len);
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+ res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
+ pkex->Mx, curve->prime_len,
+ pkex->Nx, curve->prime_len, pkex->code,
+ Kx, Kx_len, pkex->z, curve->hash_len);
+ os_memset(Kx, 0, Kx_len);
+ if (res < 0)
+ goto fail;
+
+ pkex->exchange_done = 1;
+
+out:
+ BN_CTX_free(bnctx);
+ EC_POINT_free(Qi);
+ EC_POINT_free(Qr);
+ BN_free(Mx);
+ BN_free(My);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_POINT_free(M);
+ EC_POINT_free(N);
+ EC_POINT_free(X);
+ EC_KEY_free(X_ec);
+ EC_GROUP_free(group);
+ return pkex;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
+ dpp_pkex_free(pkex);
+ pkex = NULL;
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
+ const struct wpabuf *A_pub, const u8 *u)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ size_t clear_len, attr_len;
+ struct wpabuf *clear = NULL;
+ u8 *wrapped;
+ u8 octet;
+ const u8 *addr[2];
+ size_t len[2];
+
+ /* {A, u, [bootstrapping info]}z */
+ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* A in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(A_pub));
+ wpabuf_put_buf(clear, A_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
+ goto skip_i_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len - 1);
+ wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
+ goto skip_i_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* u in I-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = DPP_HDR_LEN;
+ octet = 0;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(pkex->z, curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ const u8 *peer_mac,
+ const u8 *buf, size_t buflen)
+{
+ const u8 *attr_status, *attr_id, *attr_key, *attr_group;
+ u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
+ EC_GROUP *group = NULL;
+ BN_CTX *bnctx = NULL;
+ struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
+ BIGNUM *Nx = NULL, *Ny = NULL;
+ EC_KEY *Y_ec = NULL;
+ size_t Jx_len, Kx_len;
+ u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 u[DPP_MAX_HASH_LEN];
+ int res;
+
+ if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX Exchange Response");
+ pkex->failed = 1;
+ return NULL;
+ }
+
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+
+ attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
+ &attr_status_len);
+ if (!attr_status || attr_status_len != 1) {
+ dpp_pkex_fail(pkex, "No DPP Status attribute");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
+
+ if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
+ attr_group = dpp_get_attr(buf, buflen,
+ DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (attr_group && attr_group_len == 2) {
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Peer indicated mismatching PKEX group - proposed %u",
+ WPA_GET_LE16(attr_group));
+ return NULL;
+ }
+ }
+
+ if (attr_status[0] != DPP_STATUS_OK) {
+ dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
+ return NULL;
+ }
+
+ attr_id_len = 0;
+ attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
+ &attr_id_len);
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
+ pkex->identifier)) {
+ dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
+ return NULL;
+ }
+
+ /* N in Encrypted Key attribute */
+ attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
+ dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
+ return NULL;
+ }
+
+ /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
+ pkex->identifier, bnctx, &group);
+ if (!Qr)
+ goto fail;
+
+ /* Y' = N - Qr */
+ Y = EC_POINT_new(group);
+ N = EC_POINT_new(group);
+ Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+ Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+ if (!Y || !N || !Nx || !Ny ||
+ EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, N) ||
+ !EC_POINT_is_on_curve(group, N, bnctx) ||
+ EC_POINT_invert(group, Qr, bnctx) != 1 ||
+ EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, Y) ||
+ !EC_POINT_is_on_curve(group, Y, bnctx)) {
+ dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
+ pkex->t++;
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: N", group, N);
+ dpp_debug_print_point("DPP: Y'", group, Y);
+
+ pkex->exchange_done = 1;
+
+ /* ECDH: J = a * Y' */
+ Y_ec = EC_KEY_new();
+ if (!Y_ec ||
+ EC_KEY_set_group(Y_ec, group) != 1 ||
+ EC_KEY_set_public_key(Y_ec, Y) != 1)
+ goto fail;
+ pkex->y = EVP_PKEY_new();
+ if (!pkex->y ||
+ EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
+ goto fail;
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
+ Jx, Jx_len);
+
+ /* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x) */
+ A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ if (!A_pub || !Y_pub || !X_pub)
+ goto fail;
+ addr[0] = pkex->own_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(A_pub);
+ len[1] = wpabuf_len(A_pub) / 2;
+ addr[2] = wpabuf_head(Y_pub);
+ len[2] = wpabuf_len(Y_pub) / 2;
+ addr[3] = wpabuf_head(X_pub);
+ len[3] = wpabuf_len(X_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
+
+ /* K = x * Y' */
+ if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+ Kx, Kx_len);
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+ res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
+ pkex->Mx, curve->prime_len,
+ attr_key /* N.x */, attr_key_len / 2,
+ pkex->code, Kx, Kx_len,
+ pkex->z, curve->hash_len);
+ os_memset(Kx, 0, Kx_len);
+ if (res < 0)
+ goto fail;
+
+ msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
+ if (!msg)
+ goto fail;
+
+out:
+ wpabuf_free(A_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ EC_POINT_free(Qr);
+ EC_POINT_free(Y);
+ EC_POINT_free(N);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_KEY_free(Y_ec);
+ BN_CTX_free(bnctx);
+ EC_GROUP_free(group);
+ return msg;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
+ const struct wpabuf *B_pub, const u8 *v)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 octet;
+ u8 *wrapped;
+ struct wpabuf *clear = NULL;
+ size_t clear_len, attr_len;
+
+ /* {B, v [bootstrapping info]}z */
+ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* B in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(B_pub));
+ wpabuf_put_buf(clear, B_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
+ goto skip_r_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len - 1);
+ wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
+ goto skip_r_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* v in R-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_r_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = DPP_HDR_LEN;
+ octet = 1;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(pkex->z, curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
+ const u8 *hdr,
+ const u8 *buf, size_t buflen)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ size_t Jx_len, Lx_len;
+ u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ const u8 *wrapped_data, *b_key, *peer_u;
+ u16 wrapped_data_len, b_key_len, peer_u_len = 0;
+ const u8 *addr[4];
+ size_t len[4];
+ u8 octet;
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+ struct wpabuf *B_pub = NULL;
+ u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Request");
+ pkex->failed = 1;
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ octet = 0;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (aes_siv_decrypt(pkex->z, curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->failed = 1;
+ pkex->t++;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
+ &b_key_len);
+ if (!b_key || b_key_len != 2 * curve->prime_len) {
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
+ goto fail;
+ }
+ pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
+ b_key_len);
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Peer bootstrap public key",
+ pkex->peer_bootstrap_key);
+
+ /* ECDH: J' = y * A' */
+ if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
+ Jx, Jx_len);
+
+ /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
+ A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ if (!A_pub || !Y_pub || !X_pub)
+ goto fail;
+ addr[0] = pkex->peer_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(A_pub);
+ len[1] = wpabuf_len(A_pub) / 2;
+ addr[2] = wpabuf_head(Y_pub);
+ len[2] = wpabuf_len(Y_pub) / 2;
+ addr[3] = wpabuf_head(X_pub);
+ len[3] = wpabuf_len(X_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+ goto fail;
+
+ peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
+ &peer_u_len);
+ if (!peer_u || peer_u_len != curve->hash_len ||
+ os_memcmp(peer_u, u, curve->hash_len) != 0) {
+ dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
+ u, curve->hash_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
+ pkex->t++;
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
+
+ /* ECDH: L = b * X' */
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
+ Lx, Lx_len);
+
+ /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
+ B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ if (!B_pub)
+ goto fail;
+ addr[0] = pkex->own_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(B_pub);
+ len[1] = wpabuf_len(B_pub) / 2;
+ addr[2] = wpabuf_head(X_pub);
+ len[2] = wpabuf_len(X_pub) / 2;
+ addr[3] = wpabuf_head(Y_pub);
+ len[3] = wpabuf_len(Y_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
+
+ msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
+ if (!msg)
+ goto fail;
+
+out:
+ os_free(unwrapped);
+ wpabuf_free(A_pub);
+ wpabuf_free(B_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ return msg;
+fail:
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX Commit-Reveal Request processing failed");
+ goto out;
+}
+
+
+int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
+ const u8 *buf, size_t buflen)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ const u8 *wrapped_data, *b_key, *peer_v;
+ u16 wrapped_data_len, b_key_len, peer_v_len = 0;
+ const u8 *addr[4];
+ size_t len[4];
+ u8 octet;
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ int ret = -1;
+ u8 v[DPP_MAX_HASH_LEN];
+ size_t Lx_len;
+ u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Response");
+ pkex->failed = 1;
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ octet = 1;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (aes_siv_decrypt(pkex->z, curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->t++;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
+ &b_key_len);
+ if (!b_key || b_key_len != 2 * curve->prime_len) {
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
+ goto fail;
+ }
+ pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
+ b_key_len);
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Peer bootstrap public key",
+ pkex->peer_bootstrap_key);
+
+ /* ECDH: L' = x * B' */
+ if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
+ Lx, Lx_len);
+
+ /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
+ B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ if (!B_pub || !X_pub || !Y_pub)
+ goto fail;
+ addr[0] = pkex->peer_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(B_pub);
+ len[1] = wpabuf_len(B_pub) / 2;
+ addr[2] = wpabuf_head(X_pub);
+ len[2] = wpabuf_len(X_pub) / 2;
+ addr[3] = wpabuf_head(Y_pub);
+ len[3] = wpabuf_len(Y_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+ goto fail;
+
+ peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
+ &peer_v_len);
+ if (!peer_v || peer_v_len != curve->hash_len ||
+ os_memcmp(peer_v, v, curve->hash_len) != 0) {
+ dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
+ v, curve->hash_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
+ pkex->t++;
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
+
+ ret = 0;
+out:
+ wpabuf_free(B_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ os_free(unwrapped);
+ return ret;
+fail:
+ goto out;
+}
+
+
+struct dpp_bootstrap_info *
+dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ unsigned int freq)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return NULL;
+ bi->id = dpp_next_id(dpp);
+ bi->type = DPP_BOOTSTRAP_PKEX;
+ os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+ bi->num_freq = 1;
+ bi->freq[0] = freq;
+ bi->curve = pkex->own_bi->curve;
+ bi->pubkey = pkex->peer_bootstrap_key;
+ pkex->peer_bootstrap_key = NULL;
+ if (dpp_bootstrap_key_hash(bi) < 0) {
+ dpp_bootstrap_info_free(bi);
+ return NULL;
+ }
+ dpp_pkex_free(pkex);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+void dpp_pkex_free(struct dpp_pkex *pkex)
+{
+ if (!pkex)
+ return;
+
+ os_free(pkex->identifier);
+ os_free(pkex->code);
+ EVP_PKEY_free(pkex->x);
+ EVP_PKEY_free(pkex->y);
+ EVP_PKEY_free(pkex->peer_bootstrap_key);
+ wpabuf_free(pkex->exchange_req);
+ wpabuf_free(pkex->exchange_resp);
+ os_free(pkex);
+}
diff --git a/contrib/wpa/src/common/dpp_reconfig.c b/contrib/wpa/src/common/dpp_reconfig.c
new file mode 100644
index 000000000000..c4a027363fce
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_reconfig.c
@@ -0,0 +1,958 @@
+/*
+ * DPP reconfiguration
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+
+#include "utils/common.h"
+#include "utils/json.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+
+#ifdef CONFIG_DPP2
+
+static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id)
+{
+ struct wpabuf *msg = NULL;
+ EVP_PKEY *csign = NULL;
+ const unsigned char *p;
+ struct wpabuf *uncomp;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+ int res;
+ size_t attr_len;
+ const struct dpp_curve_params *own_curve;
+ EVP_PKEY *own_key;
+ struct wpabuf *a_nonce = NULL, *e_id = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
+
+ own_key = dpp_set_keypair(&own_curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to parse local C-sign-key information");
+ goto fail;
+ }
+
+ uncomp = dpp_get_pubkey_point(csign, 1);
+ EVP_PKEY_free(csign);
+ if (!uncomp)
+ goto fail;
+ addr[0] = wpabuf_head(uncomp);
+ len[0] = wpabuf_len(uncomp);
+ wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
+ res = sha256_vector(1, addr, len, hash);
+ wpabuf_free(uncomp);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
+ hash, SHA256_MAC_LEN);
+
+ if (dpp_update_reconfig_id(id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
+ goto fail;
+ }
+
+ a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
+ e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
+ if (!a_nonce || !e_id)
+ goto fail;
+
+ attr_len = 4 + SHA256_MAC_LEN;
+ attr_len += 4 + 2;
+ attr_len += 4 + wpabuf_len(a_nonce);
+ attr_len += 4 + wpabuf_len(e_id);
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
+ if (!msg)
+ goto fail;
+
+ /* Configurator C-sign key Hash */
+ dpp_build_attr_csign_key_hash(msg, hash);
+
+ /* Finite Cyclic Group attribute */
+ wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
+ own_curve->ike_group);
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, own_curve->ike_group);
+
+ /* A-NONCE */
+ wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
+ wpabuf_put_le16(msg, wpabuf_len(a_nonce));
+ wpabuf_put_buf(msg, a_nonce);
+
+ /* E'-id */
+ wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
+ wpabuf_put_le16(msg, wpabuf_len(e_id));
+ wpabuf_put_buf(msg, e_id);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Reconfig Announcement frame attributes", msg);
+fail:
+ wpabuf_free(a_nonce);
+ wpabuf_free(e_id);
+ EVP_PKEY_free(own_key);
+ return msg;
+}
+
+
+static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
+{
+ struct wpabuf *msg;
+ size_t attr_len;
+
+ /* Build DPP Reconfig Authentication Request frame attributes */
+ attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
+ 4 + auth->curve->nonce_len;
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len);
+ if (!msg)
+ return NULL;
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, auth->transaction_id);
+
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+
+ /* DPP Connector */
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
+ wpabuf_put_str(msg, auth->conf->connector);
+
+ /* C-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
+ wpabuf_put_le16(msg, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Reconfig Authentication Request frame attributes",
+ msg);
+
+ return msg;
+}
+
+
+static int
+dpp_configurator_build_own_connector(struct dpp_configurator *conf,
+ const struct dpp_curve_params *curve)
+{
+ struct wpabuf *dppcon = NULL;
+ int ret = -1;
+
+ if (conf->connector)
+ return 0; /* already generated */
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sign own Configurator Connector for reconfiguration with curve %s",
+ conf->curve->name);
+ conf->connector_key = dpp_gen_keypair(curve);
+ if (!conf->connector_key)
+ goto fail;
+
+ /* Connector (JSON dppCon object) */
+ dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
+ if (!dppcon)
+ goto fail;
+ json_start_object(dppcon, NULL);
+ json_start_array(dppcon, "groups");
+ json_start_object(dppcon, NULL);
+ json_add_string(dppcon, "groupId", "*");
+ json_value_sep(dppcon);
+ json_add_string(dppcon, "netRole", "configurator");
+ json_end_object(dppcon);
+ json_end_array(dppcon);
+ json_value_sep(dppcon);
+ if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
+ curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
+ goto fail;
+ }
+ json_end_object(dppcon);
+ wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
+ (const char *) wpabuf_head(dppcon));
+
+ conf->connector = dpp_sign_connector(conf, dppcon);
+ if (!conf->connector)
+ goto fail;
+ wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector);
+
+ ret = 0;
+fail:
+ wpabuf_free(dppcon);
+ return ret;
+}
+
+
+struct dpp_authentication *
+dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len)
+{
+ struct dpp_authentication *auth;
+ const struct dpp_curve_params *curve;
+ EVP_PKEY *a_nonce, *e_prime_id;
+ EC_POINT *e_id;
+
+ curve = dpp_get_curve_ike_group(group);
+ if (!curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported group %u - cannot reconfigure",
+ group);
+ return NULL;
+ }
+
+ if (!a_nonce_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
+ a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
+ if (!a_nonce) {
+ wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
+ return NULL;
+ }
+ dpp_debug_print_key("A-NONCE", a_nonce);
+
+ if (!e_id_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
+ return NULL;
+ }
+ e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
+ if (!e_prime_id) {
+ wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
+ EVP_PKEY_free(a_nonce);
+ return NULL;
+ }
+ dpp_debug_print_key("E'-id", e_prime_id);
+ e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
+ EVP_PKEY_free(a_nonce);
+ EVP_PKEY_free(e_prime_id);
+ if (!e_id) {
+ wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
+ return NULL;
+ }
+ /* TODO: could use E-id to determine whether reconfiguration with this
+ * Enrollee has already been started and is waiting for updated
+ * configuration instead of replying again before such configuration
+ * becomes available */
+ EC_POINT_clear_free(e_id);
+
+ auth = dpp_alloc_auth(dpp, msg_ctx);
+ if (!auth)
+ return NULL;
+
+ auth->conf = conf;
+ auth->reconfig = 1;
+ auth->initiator = 1;
+ auth->waiting_auth_resp = 1;
+ auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ auth->configurator = 1;
+ auth->curve = curve;
+ auth->transaction_id = 1;
+ if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
+ goto fail;
+
+ if (dpp_configurator_build_own_connector(conf, curve) < 0)
+ goto fail;
+
+ if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
+ goto fail;
+ }
+
+ auth->reconfig_req_msg = dpp_reconfig_build_req(auth);
+ if (!auth->reconfig_req_msg)
+ goto fail;
+
+out:
+ return auth;
+fail:
+ dpp_auth_deinit(auth);
+ auth = NULL;
+ goto out;
+}
+
+
+static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
+ const char *own_connector,
+ struct wpabuf *conn_status)
+{
+ struct wpabuf *msg = NULL, *clear, *pr = NULL;
+ u8 *attr_start, *attr_end;
+ size_t clear_len, attr_len, len[2];
+ const u8 *addr[2];
+ u8 *wrapped;
+ int res = -1;
+
+ /* Build DPP Reconfig Authentication Response frame attributes */
+ clear_len = 4 + auth->curve->nonce_len +
+ 4 + wpabuf_len(conn_status);
+ clear = wpabuf_alloc(clear_len);
+ if (!clear)
+ goto fail;
+
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
+ wpabuf_put_le16(clear, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
+
+ /* Connection Status (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(conn_status));
+ wpabuf_put_buf(clear, conn_status);
+
+ pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pr)
+ goto fail;
+
+ attr_len = 4 + 1 + 4 + 1 +
+ 4 + os_strlen(own_connector) +
+ 4 + auth->curve->nonce_len +
+ 4 + wpabuf_len(pr) +
+ 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
+ if (!msg)
+ goto fail;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, auth->transaction_id);
+
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+
+ /* R-Connector */
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(own_connector));
+ wpabuf_put_str(msg, own_connector);
+
+ /* E-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(msg, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
+
+ /* Responder Protocol Key (Pr) */
+ wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pr));
+ wpabuf_put_buf(msg, pr);
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Reconfig Authentication Response frame attributes",
+ msg);
+
+ wpabuf_free(auth->reconfig_resp_msg);
+ auth->reconfig_resp_msg = msg;
+
+ res = 0;
+out:
+ wpabuf_free(clear);
+ wpabuf_free(pr);
+ return res;
+fail:
+ wpabuf_free(msg);
+ goto out;
+}
+
+
+struct dpp_authentication *
+dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
+ const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ unsigned int freq, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ struct dpp_authentication *auth = NULL;
+ const u8 *trans_id, *version, *i_connector, *c_nonce;
+ u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
+ struct dpp_signed_connector_info info;
+ enum dpp_status_error res;
+ struct json_token *root = NULL, *own_root = NULL, *token;
+ unsigned char *own_conn = NULL;
+ struct wpabuf *conn_status = NULL;
+
+ os_memset(&info, 0, sizeof(info));
+
+ trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ goto fail;
+ }
+
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len < 1 || version[0] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid Protocol Version attribute");
+ goto fail;
+ }
+
+ i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
+ &i_connector_len);
+ if (!i_connector) {
+ wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
+ i_connector, i_connector_len);
+
+ c_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid C-nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
+
+ res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
+ i_connector, i_connector_len);
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector");
+ goto fail;
+ }
+
+ root = json_parse((const char *) info.payload, info.payload_len);
+ own_root = dpp_parse_own_connector(own_connector);
+ if (!root || !own_root ||
+ !dpp_connector_match_groups(own_root, root, true)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: I-Connector does not include compatible group netrole with own connector");
+ goto fail;
+ }
+
+ token = json_get_member(root, "expiry");
+ if (token && token->type == JSON_STRING &&
+ dpp_key_expired(token->string, NULL)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: I-Connector (netAccessKey) has expired");
+ goto fail;
+ }
+
+ token = json_get_member(root, "netAccessKey");
+ if (!token || token->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
+ goto fail;
+ }
+
+ auth = dpp_alloc_auth(dpp, msg_ctx);
+ if (!auth)
+ return NULL;
+
+ auth->reconfig = 1;
+ auth->allowed_roles = DPP_CAPAB_ENROLLEE;
+ if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
+ goto fail;
+
+ auth->transaction_id = trans_id[0];
+
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+
+ os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
+
+ if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
+ net_access_key_len, token) < 0)
+ goto fail;
+
+ if (c_nonce_len != auth->curve->nonce_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
+ c_nonce_len, auth->curve->nonce_len);
+ goto fail;
+ }
+
+ /* Build Connection Status object */
+ /* TODO: Get appropriate result value */
+ /* TODO: ssid64 and channelList */
+ conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL);
+ if (!conn_status)
+ goto fail;
+
+ if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0)
+ goto fail;
+
+out:
+ os_free(info.payload);
+ os_free(own_conn);
+ json_free(root);
+ json_free(own_root);
+ wpabuf_free(conn_status);
+ return auth;
+fail:
+ dpp_auth_deinit(auth);
+ auth = NULL;
+ goto out;
+}
+
+
+struct wpabuf *
+dpp_reconfig_build_conf(struct dpp_authentication *auth)
+{
+ struct wpabuf *msg = NULL, *clear;
+ u8 *attr_start, *attr_end;
+ size_t clear_len, attr_len, len[2];
+ const u8 *addr[2];
+ u8 *wrapped;
+ u8 flags;
+
+ /* Build DPP Reconfig Authentication Confirm frame attributes */
+ clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
+ 4 + 1;
+ clear = wpabuf_alloc(clear_len);
+ if (!clear)
+ goto fail;
+
+ /* Transaction ID */
+ wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(clear, 1);
+ wpabuf_put_u8(clear, auth->transaction_id);
+
+ /* Protocol Version */
+ wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(clear, 1);
+ wpabuf_put_u8(clear, auth->peer_version);
+
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
+ wpabuf_put_le16(clear, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
+
+ /* E-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len);
+
+ /* Reconfig-Flags (wrapped) */
+ flags = DPP_CONFIG_REPLACEKEY;
+ wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
+ wpabuf_put_le16(clear, 1);
+ wpabuf_put_u8(clear, flags);
+
+ attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
+ attr_len += 4 + 1;
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
+ if (!msg)
+ goto fail;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Reconfig Authentication Confirm frame attributes",
+ msg);
+
+out:
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf *
+dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
+ *c_nonce, *e_nonce, *conn_status;
+ u16 trans_id_len, version_len, r_connector_len, r_proto_len,
+ wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
+ struct wpabuf *conf = NULL;
+ char *signed_connector = NULL;
+ struct dpp_signed_connector_info info;
+ enum dpp_status_error res;
+ struct json_token *root = NULL, *token, *conn_status_json = NULL;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+
+ os_memset(&info, 0, sizeof(info));
+
+ if (!auth->reconfig || !auth->configurator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+ wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ dpp_auth_fail(auth, "Peer did not include Transaction ID");
+ goto fail;
+ }
+ if (trans_id[0] != auth->transaction_id) {
+ dpp_auth_fail(auth, "Transaction ID mismatch");
+ goto fail;
+ }
+
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len < 1 || version[0] < 2) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Protocol Version attribute");
+ goto fail;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+
+ r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
+ &r_connector_len);
+ if (!r_connector) {
+ dpp_auth_fail(auth, " Missing R-Connector attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
+ r_connector, r_connector_len);
+
+ e_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
+ os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+
+ r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
+ &r_proto_len);
+ if (!r_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
+ r_proto, r_proto_len);
+
+ signed_connector = os_malloc(r_connector_len + 1);
+ if (!signed_connector)
+ goto fail;
+ os_memcpy(signed_connector, r_connector, r_connector_len);
+ signed_connector[r_connector_len] = '\0';
+
+ res = dpp_process_signed_connector(&info, auth->conf->csign,
+ signed_connector);
+ if (res != DPP_STATUS_OK) {
+ dpp_auth_fail(auth, "Invalid R-Connector");
+ goto fail;
+ }
+
+ root = json_parse((const char *) info.payload, info.payload_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Invalid Connector payload");
+ goto fail;
+ }
+
+ /* Do not check netAccessKey expiration for reconfiguration to allow
+ * expired Connector to be updated. */
+
+ token = json_get_member(root, "netAccessKey");
+ if (!token || token->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No netAccessKey object found");
+ goto fail;
+ }
+
+ if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len,
+ token) < 0)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
+
+ conn_status = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONN_STATUS, &conn_status_len);
+ if (!conn_status) {
+ dpp_auth_fail(auth, "Missing Connection Status attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus",
+ conn_status, conn_status_len);
+
+ conn_status_json = json_parse((const char *) conn_status,
+ conn_status_len);
+ if (!conn_status_json) {
+ dpp_auth_fail(auth, "Could not parse connStatus");
+ goto fail;
+ }
+ /* TODO: use connStatus information */
+
+ conf = dpp_reconfig_build_conf(auth);
+ if (conf)
+ auth->reconfig_success = true;
+
+out:
+ json_free(root);
+ json_free(conn_status_json);
+ bin_clear_free(unwrapped, unwrapped_len);
+ os_free(info.payload);
+ os_free(signed_connector);
+ return conf;
+fail:
+ wpabuf_free(conf);
+ conf = NULL;
+ goto out;
+}
+
+
+int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
+ *reconfig_flags, *status;
+ u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
+ e_nonce_len, reconfig_flags_len, status_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ int res = -1;
+ u8 flags;
+
+ if (!auth->reconfig || auth->configurator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+ wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth,
+ "Reconfiguration did not complete successfully");
+ goto fail;
+ }
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ trans_id = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_TRANSACTION_ID, &trans_id_len);
+ if (!trans_id || trans_id_len != 1 ||
+ trans_id[0] != auth->transaction_id) {
+ dpp_auth_fail(auth,
+ "Peer did not include valid Transaction ID");
+ goto fail;
+ }
+
+ version = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_PROTOCOL_VERSION, &version_len);
+ if (!version || version_len < 1 || version[0] != DPP_VERSION) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Protocol Version attribute");
+ goto fail;
+ }
+
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
+
+ reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_RECONFIG_FLAGS,
+ &reconfig_flags_len);
+ if (!reconfig_flags || reconfig_flags_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
+ goto fail;
+ }
+ flags = reconfig_flags[0] & BIT(0);
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
+ auth->reconfig_connector_key = flags;
+
+ auth->reconfig_success = true;
+ res = 0;
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return res;
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/common/dpp_tcp.c b/contrib/wpa/src/common/dpp_tcp.c
new file mode 100644
index 000000000000..c373f107791c
--- /dev/null
+++ b/contrib/wpa/src/common/dpp_tcp.c
@@ -0,0 +1,1824 @@
+/*
+ * DPP over TCP
+ * Copyright (c) 2019-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "utils/ip_addr.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+#ifdef CONFIG_DPP2
+
+struct dpp_connection {
+ struct dl_list list;
+ struct dpp_controller *ctrl;
+ struct dpp_relay_controller *relay;
+ struct dpp_global *global;
+ struct dpp_authentication *auth;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ int sock;
+ u8 mac_addr[ETH_ALEN];
+ unsigned int freq;
+ u8 msg_len[4];
+ size_t msg_len_octets;
+ struct wpabuf *msg;
+ struct wpabuf *msg_out;
+ size_t msg_out_pos;
+ unsigned int read_eloop:1;
+ unsigned int write_eloop:1;
+ unsigned int on_tcp_tx_complete_gas_done:1;
+ unsigned int on_tcp_tx_complete_remove:1;
+ unsigned int on_tcp_tx_complete_auth_ok:1;
+ unsigned int gas_comeback_in_progress:1;
+ u8 gas_dialog_token;
+ char *name;
+ enum dpp_netrole netrole;
+};
+
+/* Remote Controller */
+struct dpp_relay_controller {
+ struct dl_list list;
+ struct dpp_global *global;
+ u8 pkhash[SHA256_MAC_LEN];
+ struct hostapd_ip_addr ipaddr;
+ void *msg_ctx;
+ void *cb_ctx;
+ void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
+ size_t len);
+ void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
+ int prot, struct wpabuf *buf);
+ struct dl_list conn; /* struct dpp_connection */
+};
+
+/* Local Controller */
+struct dpp_controller {
+ struct dpp_global *global;
+ u8 allowed_roles;
+ int qr_mutual;
+ int sock;
+ struct dl_list conn; /* struct dpp_connection */
+ char *configurator_params;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+};
+
+static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
+static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
+static void dpp_controller_auth_success(struct dpp_connection *conn,
+ int initiator);
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx);
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
+static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
+static void dpp_connection_free(struct dpp_connection *conn)
+{
+ if (conn->sock >= 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
+ conn->sock);
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ close(conn->sock);
+ }
+ eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
+ eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL);
+ wpabuf_free(conn->msg);
+ wpabuf_free(conn->msg_out);
+ dpp_auth_deinit(conn->auth);
+ os_free(conn->name);
+ os_free(conn);
+}
+
+
+static void dpp_connection_remove(struct dpp_connection *conn)
+{
+ dl_list_del(&conn->list);
+ dpp_connection_free(conn);
+}
+
+
+int dpp_relay_add_controller(struct dpp_global *dpp,
+ struct dpp_relay_config *config)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return -1;
+
+ ctrl = os_zalloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -1;
+ dl_list_init(&ctrl->conn);
+ ctrl->global = dpp;
+ os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
+ os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
+ ctrl->msg_ctx = config->msg_ctx;
+ ctrl->cb_ctx = config->cb_ctx;
+ ctrl->tx = config->tx;
+ ctrl->gas_resp_tx = config->gas_resp_tx;
+ dl_list_add(&dpp->controllers, &ctrl->list);
+ return 0;
+}
+
+
+static struct dpp_relay_controller *
+dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
+ list) {
+ if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
+ return ctrl;
+ }
+
+ return NULL;
+}
+
+
+static struct dpp_relay_controller *
+dpp_relay_controller_get_ctx(struct dpp_global *dpp, void *cb_ctx)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
+ list) {
+ if (cb_ctx == ctrl->cb_ctx)
+ return ctrl;
+ }
+
+ return NULL;
+}
+
+
+static void dpp_controller_gas_done(struct dpp_connection *conn)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ if (auth->waiting_csr) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ conn->on_tcp_tx_complete_gas_done = 0;
+ return;
+ }
+
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ return;
+ }
+
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ dpp_connection_remove(conn);
+}
+
+
+static int dpp_tcp_send(struct dpp_connection *conn)
+{
+ int res;
+
+ if (!conn->msg_out) {
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ conn->write_eloop = 0;
+ return -1;
+ }
+ res = send(conn->sock,
+ wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
+ wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
+ strerror(errno));
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->msg_out_pos += res;
+ if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: %u/%u bytes of message sent to Controller",
+ (unsigned int) conn->msg_out_pos,
+ (unsigned int) wpabuf_len(conn->msg_out));
+ if (!conn->write_eloop &&
+ eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) == 0)
+ conn->write_eloop = 1;
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
+ wpabuf_free(conn->msg_out);
+ conn->msg_out = NULL;
+ conn->msg_out_pos = 0;
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ conn->write_eloop = 0;
+ if (!conn->read_eloop &&
+ eloop_register_sock(conn->sock, EVENT_TYPE_READ,
+ dpp_controller_rx, conn, NULL) == 0)
+ conn->read_eloop = 1;
+ if (conn->on_tcp_tx_complete_remove) {
+ dpp_connection_remove(conn);
+ } else if (conn->auth && (conn->ctrl || conn->auth->configurator) &&
+ conn->on_tcp_tx_complete_gas_done) {
+ dpp_controller_gas_done(conn);
+ } else if (conn->on_tcp_tx_complete_auth_ok) {
+ conn->on_tcp_tx_complete_auth_ok = 0;
+ dpp_controller_auth_success(conn, 1);
+ }
+
+ return 0;
+}
+
+
+static int dpp_tcp_send_msg(struct dpp_connection *conn,
+ const struct wpabuf *msg)
+{
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
+ if (!conn->msg_out)
+ return -1;
+ wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
+ wpabuf_len(msg) - 1);
+
+ if (dpp_tcp_send(conn) == 1) {
+ if (!conn->write_eloop) {
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready,
+ conn, NULL) < 0)
+ return -1;
+ conn->write_eloop = 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void dpp_controller_start_gas_client(struct dpp_connection *conn)
+{
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *buf;
+ const char *dpp_name;
+
+ dpp_name = conn->name ? conn->name : "Test";
+ buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, NULL,
+ NULL);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return;
+ }
+
+ dpp_tcp_send_msg(conn, buf);
+ wpabuf_free(buf);
+}
+
+
+static void dpp_controller_auth_success(struct dpp_connection *conn,
+ int initiator)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
+ wpa_msg(conn->msg_ctx, MSG_INFO,
+ DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ if (auth->configurator) {
+ /* Prevent GAS response */
+ auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->configurator)
+ dpp_controller_start_gas_client(conn);
+}
+
+
+static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
+ dpp_tcp_send(conn);
+}
+
+
+static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
+ const struct hostapd_ip_addr *ipaddr,
+ int port)
+{
+ struct sockaddr_in *dst;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 *dst6;
+#endif /* CONFIG_IPV6 */
+
+ switch (ipaddr->af) {
+ case AF_INET:
+ dst = (struct sockaddr_in *) addr;
+ os_memset(dst, 0, sizeof(*dst));
+ dst->sin_family = AF_INET;
+ dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
+ dst->sin_port = htons(port);
+ *addrlen = sizeof(*dst);
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *) addr;
+ os_memset(dst6, 0, sizeof(*dst6));
+ dst6->sin6_family = AF_INET6;
+ os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
+ sizeof(struct in6_addr));
+ dst6->sin6_port = htons(port);
+ *addrlen = sizeof(*dst6);
+ break;
+#endif /* CONFIG_IPV6 */
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for relayed connection to complete");
+ dpp_connection_remove(conn);
+}
+
+
+static struct dpp_connection *
+dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
+ unsigned int freq)
+{
+ struct dpp_connection *conn;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ char txt[100];
+
+ if (dl_list_len(&ctrl->conn) >= 15) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
+ return NULL;
+ }
+
+ if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
+ &ctrl->ipaddr, DPP_TCP_PORT) < 0)
+ return NULL;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ return NULL;
+
+ conn->global = ctrl->global;
+ conn->relay = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
+ os_memcpy(conn->mac_addr, src, ETH_ALEN);
+ conn->freq = freq;
+
+ conn->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (conn->sock < 0)
+ goto fail;
+ wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
+ conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
+ if (errno != EINPROGRESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /*
+ * Continue connecting in the background; eloop will call us
+ * once the connection is ready (or failed).
+ */
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) < 0)
+ goto fail;
+ conn->write_eloop = 1;
+
+ eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL);
+ eloop_register_timeout(20, 0, dpp_relay_conn_timeout, conn, NULL);
+
+ dl_list_add(&ctrl->conn, &conn->list);
+ return conn;
+fail:
+ dpp_connection_free(conn);
+ return NULL;
+}
+
+
+static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct wpabuf *msg;
+
+ msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
+ if (!msg)
+ return NULL;
+ wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
+ wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
+ wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
+ wpabuf_put_data(msg, buf, len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+ return msg;
+}
+
+
+static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ u8 type = hdr[DPP_HDR_LEN - 1];
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue already established Relay/Controller connection for this session");
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
+ if (!conn->msg_out) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
+ * TX status */
+ if (type == DPP_PA_CONFIGURATION_RESULT)
+ conn->on_tcp_tx_complete_remove = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len, unsigned int freq,
+ const u8 *i_bootstrap, const u8 *r_bootstrap,
+ void *cb_ctx)
+{
+ struct dpp_relay_controller *ctrl;
+ struct dpp_connection *conn;
+ u8 type = hdr[DPP_HDR_LEN - 1];
+
+ /* Check if there is an already started session for this peer and if so,
+ * continue that session (send this over TCP) and return 0.
+ */
+ if (type != DPP_PA_PEER_DISCOVERY_REQ &&
+ type != DPP_PA_PEER_DISCOVERY_RESP &&
+ type != DPP_PA_PRESENCE_ANNOUNCEMENT &&
+ type != DPP_PA_RECONFIG_ANNOUNCEMENT) {
+ dl_list_for_each(ctrl, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ dl_list_for_each(conn, &ctrl->conn,
+ struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr,
+ ETH_ALEN) == 0)
+ return dpp_relay_tx(conn, hdr, buf, len);
+ }
+ }
+ }
+
+ if (type == DPP_PA_PRESENCE_ANNOUNCEMENT ||
+ type == DPP_PA_RECONFIG_ANNOUNCEMENT) {
+ /* TODO: Could send this to all configured Controllers. For now,
+ * only the first Controller is supported. */
+ ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx);
+ } else {
+ if (!r_bootstrap)
+ return -1;
+ ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+ }
+ if (!ctrl)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication Request for a configured Controller");
+ conn = dpp_relay_new_conn(ctrl, src, freq);
+ if (!conn)
+ return -1;
+
+ conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
+ if (!conn->msg_out) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+ /* Message will be sent in dpp_conn_tx_ready() */
+
+ return 0;
+}
+
+
+int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
+ size_t data_len)
+{
+ struct dpp_relay_controller *ctrl;
+ struct dpp_connection *conn, *found = NULL;
+ struct wpabuf *msg;
+
+ /* Check if there is a successfully completed authentication for this
+ * and if so, continue that session (send this over TCP) and return 0.
+ */
+ dl_list_for_each(ctrl, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ if (found)
+ break;
+ dl_list_for_each(conn, &ctrl->conn,
+ struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr,
+ ETH_ALEN) == 0) {
+ found = conn;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ msg = wpabuf_alloc(4 + 1 + data_len);
+ if (!msg)
+ return -1;
+ wpabuf_put_be32(msg, 1 + data_len);
+ wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
+ wpabuf_put_data(msg, data, data_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = msg;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static void dpp_controller_free(struct dpp_controller *ctrl)
+{
+ struct dpp_connection *conn, *tmp;
+
+ if (!ctrl)
+ return;
+
+ dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+
+ if (ctrl->sock >= 0) {
+ close(ctrl->sock);
+ eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
+ }
+ os_free(ctrl->configurator_params);
+ os_free(ctrl);
+}
+
+
+static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+
+ i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+
+ /* Try to find own and peer bootstrapping key matches based on the
+ * received hash values */
+ dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
+ &own_bi, &peer_bi);
+ if (!own_bi) {
+ wpa_printf(MSG_INFO,
+ "No matching own bootstrapping key found - ignore message");
+ return -1;
+ }
+
+ if (conn->auth) {
+ wpa_printf(MSG_INFO,
+ "Already in DPP authentication exchange - ignore new one");
+ return 0;
+ }
+
+ conn->auth = dpp_auth_req_rx(conn->ctrl->global, conn->msg_ctx,
+ conn->ctrl->allowed_roles,
+ conn->ctrl->qr_mutual,
+ peer_bi, own_bi, -1, hdr, buf, len);
+ if (!conn->auth) {
+ wpa_printf(MSG_DEBUG, "DPP: No response generated");
+ return -1;
+ }
+
+ if (dpp_set_configurator(conn->auth,
+ conn->ctrl->configurator_params) < 0) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
+}
+
+
+static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *msg;
+ int res;
+
+ if (!auth)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
+
+ msg = dpp_auth_resp_rx(auth, hdr, buf, len);
+ if (!msg) {
+ if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start wait for full response");
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->on_tcp_tx_complete_auth_ok = 1;
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
+ return res;
+}
+
+
+static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return -1;
+ }
+
+ if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ return -1;
+ }
+
+ dpp_controller_auth_success(conn, 0);
+ return 0;
+}
+
+
+void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ if (!conn->auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(conn->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_connection_remove(conn);
+}
+
+
+static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+ void *msg_ctx = conn->msg_ctx;
+
+ if (!conn->ctrl && (!auth || !auth->configurator))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return -1;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(
+ dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ eloop_register_timeout(
+ 16, 0, dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ return 0;
+ }
+ if (status == DPP_STATUS_OK)
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ return -1; /* to remove the completed connection */
+}
+
+
+static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return -1;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ return -1; /* to remove the completed connection */
+}
+
+
+static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+ struct dpp_global *dpp = conn->ctrl->global;
+
+ if (conn->auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return -1;
+ }
+
+ auth = dpp_auth_init(dpp, conn->msg_ctx, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
+ if (!auth)
+ return -1;
+ if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->auth = auth;
+ return dpp_tcp_send_msg(conn, conn->auth->req_msg);
+}
+
+
+static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
+ struct dpp_configurator *conf;
+ struct dpp_global *dpp = conn->ctrl->global;
+ struct dpp_authentication *auth;
+ u16 group;
+
+ if (conn->auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement");
+
+ csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+ &csign_hash_len);
+ if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Configurator C-sign key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+ csign_hash, csign_hash_len);
+ conf = dpp_configurator_find_kid(dpp, csign_hash);
+ if (!conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching Configurator information found");
+ return -1;
+ }
+
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return -1;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(dpp, conn->msg_ctx, conf, 0, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
+ if (!auth)
+ return -1;
+ if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return -1;
+ }
+
+ conn->auth = auth;
+ return dpp_tcp_send_msg(conn, auth->reconfig_req_msg);
+}
+
+
+static int dpp_controller_rx_reconfig_auth_resp(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *conf;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response");
+
+ if (!auth || !auth->reconfig || !auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return -1;
+ }
+
+ conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+ if (!conf)
+ return -1;
+
+ res = dpp_tcp_send_msg(conn, conf);
+ wpabuf_free(conf);
+ return res;
+}
+
+
+static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+{
+ const u8 *pos, *end;
+ u8 type;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
+ pos = msg;
+ end = msg + len;
+
+ if (end - pos < DPP_HDR_LEN ||
+ WPA_GET_BE24(pos) != OUI_WFA ||
+ pos[3] != DPP_OUI_TYPE) {
+ wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
+ return -1;
+ }
+
+ if (pos[4] != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
+ pos[4]);
+ return -1;
+ }
+ type = pos[5];
+ wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
+ pos += DPP_HDR_LEN;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
+ pos, end - pos);
+ if (dpp_check_attrs(pos, end - pos) < 0)
+ return -1;
+
+ if (conn->relay) {
+ wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
+ conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
+ conn->freq, msg, len);
+ return 0;
+ }
+
+ switch (type) {
+ case DPP_PA_AUTHENTICATION_REQ:
+ return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
+ case DPP_PA_AUTHENTICATION_RESP:
+ return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
+ case DPP_PA_AUTHENTICATION_CONF:
+ return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
+ case DPP_PA_CONFIGURATION_RESULT:
+ return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ return dpp_controller_rx_conn_status_result(conn, msg, pos,
+ end - pos);
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ return dpp_controller_rx_presence_announcement(conn, msg, pos,
+ end - pos);
+ case DPP_PA_RECONFIG_ANNOUNCEMENT:
+ return dpp_controller_rx_reconfig_announcement(conn, msg, pos,
+ end - pos);
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ return dpp_controller_rx_reconfig_auth_resp(conn, msg, pos,
+ end - pos);
+ default:
+ /* TODO: missing messages types */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported frame subtype %d", type);
+ return -1;
+ }
+}
+
+
+static int dpp_tcp_send_comeback_delay(struct dpp_connection *conn, u8 action)
+{
+ struct wpabuf *buf;
+ size_t len = 18;
+
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 500); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ wpabuf_put_le16(buf, 0); /* Query Response Length */
+
+ /* Send Config Response over TCP */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static int dpp_tcp_send_gas_resp(struct dpp_connection *conn, u8 action,
+ struct wpabuf *resp)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ if (!resp)
+ return -1;
+
+ len = 18 + wpabuf_len(resp);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf) {
+ wpabuf_free(resp);
+ return -1;
+ }
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, resp);
+ wpabuf_free(resp);
+
+ /* Send Config Response over TCP; GAS fragmentation is taken care of by
+ * the Relay */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ conn->on_tcp_tx_complete_gas_done = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+{
+ const u8 *pos, *end, *next;
+ const u8 *adv_proto;
+ u16 slen;
+ struct wpabuf *resp;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (len < 1 + 2)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Request over TCP");
+
+ if (!auth || (!conn->ctrl && !auth->configurator) ||
+ (!auth->auth_success && !auth->reconfig_success)) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return -1;
+ }
+
+ pos = msg;
+ end = msg + len;
+
+ conn->gas_dialog_token = *pos++;
+ adv_proto = pos++;
+ slen = *pos++;
+ if (*adv_proto != WLAN_EID_ADV_PROTO ||
+ slen > end - pos || slen < 2)
+ return -1;
+
+ next = pos + slen;
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
+ pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
+ return -1;
+
+ pos = next;
+ /* Query Request */
+ if (end - pos < 2)
+ return -1;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (slen > end - pos)
+ return -1;
+
+ resp = dpp_conf_req_rx(auth, pos, slen);
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ conn->gas_comeback_in_progress = 1;
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_INITIAL_RESP);
+ }
+
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp);
+}
+
+
+static int dpp_controller_rx_gas_comeback_req(struct dpp_connection *conn,
+ const u8 *msg, size_t len)
+{
+ u8 dialog_token;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *resp;
+
+ if (len < 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Request over TCP (comeback)");
+
+ if (!auth || (!conn->ctrl && !auth->configurator) ||
+ (!auth->auth_success && !auth->reconfig_success) ||
+ !conn->gas_comeback_in_progress) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return -1;
+ }
+
+ dialog_token = msg[0];
+ if (dialog_token != conn->gas_dialog_token) {
+ wpa_printf(MSG_DEBUG, "DPP: Dialog token mismatch (%u != %u)",
+ dialog_token, conn->gas_dialog_token);
+ return -1;
+ }
+
+ if (!auth->conf_resp_tcp) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_COMEBACK_RESP);
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configuration response is ready to be sent out");
+ resp = auth->conf_resp_tcp;
+ auth->conf_resp_tcp = NULL;
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_COMEBACK_RESP, resp);
+}
+
+
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, conn->name ? conn->name : "Test");
+ if (!auth->csr) {
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ dpp_controller_start_gas_client(conn);
+}
+
+
+static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
+{
+ struct dpp_authentication *auth = conn->auth;
+ int res;
+ struct wpabuf *msg;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configuration Response for local stack from TCP");
+
+ if (auth)
+ res = dpp_conf_resp_rx(auth, resp);
+ else
+ res = -1;
+ wpabuf_free(resp);
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
+ return 0;
+ }
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ return -1;
+ }
+
+ if (conn->process_conf_obj)
+ res = conn->process_conf_obj(conn->cb_ctx, auth);
+ else
+ res = 0;
+
+ if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ return -1;
+
+ conn->on_tcp_tx_complete_remove = 1;
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+
+ return res;
+}
+
+
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *msg;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send GAS Comeback Request");
+ msg = wpabuf_alloc(4 + 2);
+ if (!msg)
+ return;
+ wpabuf_put_be32(msg, 2);
+ wpabuf_put_u8(msg, WLAN_PA_GAS_COMEBACK_REQ);
+ wpabuf_put_u8(msg, conn->gas_dialog_token);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = msg;
+ dpp_tcp_send(conn);
+}
+
+
+static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
+ size_t len, bool comeback)
+{
+ struct wpabuf *buf;
+ u8 dialog_token;
+ const u8 *pos, *end, *next, *adv_proto;
+ u16 status, slen, comeback_delay;
+
+ if (len < (size_t) (5 + 2 + (comeback ? 1 : 0)))
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Response over TCP");
+
+ pos = msg;
+ end = msg + len;
+
+ dialog_token = *pos++;
+ status = WPA_GET_LE16(pos);
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
+ return -1;
+ }
+ pos += 2;
+ if (comeback)
+ pos++; /* ignore Fragment ID */
+ comeback_delay = WPA_GET_LE16(pos);
+ pos += 2;
+
+ adv_proto = pos++;
+ slen = *pos++;
+ if (*adv_proto != WLAN_EID_ADV_PROTO ||
+ slen > end - pos || slen < 2)
+ return -1;
+
+ next = pos + slen;
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
+ pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
+ return -1;
+
+ pos = next;
+ /* Query Response */
+ if (end - pos < 2)
+ return -1;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (slen > end - pos)
+ return -1;
+
+ if (comeback_delay) {
+ unsigned int secs, usecs;
+
+ conn->gas_dialog_token = dialog_token;
+ secs = (comeback_delay * 1024) / 1000000;
+ usecs = comeback_delay * 1024 - secs * 1000000;
+ wpa_printf(MSG_DEBUG, "DPP: Comeback delay: %u",
+ comeback_delay);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
+ eloop_register_timeout(secs, usecs, dpp_tcp_gas_query_comeback,
+ conn, NULL);
+ return 0;
+ }
+
+ buf = wpabuf_alloc(slen);
+ if (!buf)
+ return -1;
+ wpabuf_put_data(buf, pos, slen);
+
+ if (!conn->relay &&
+ (!conn->ctrl || (conn->ctrl->allowed_roles & DPP_CAPAB_ENROLLEE)))
+ return dpp_tcp_rx_gas_resp(conn, buf);
+
+ if (!conn->relay) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ wpabuf_free(buf);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
+ conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
+ dialog_token, 0, buf);
+
+ return 0;
+}
+
+
+static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ int res;
+ const u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
+ sd);
+
+ if (conn->msg_len_octets < 4) {
+ u32 msglen;
+
+ res = recv(sd, &conn->msg_len[conn->msg_len_octets],
+ 4 - conn->msg_len_octets, 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
+ strerror(errno));
+ dpp_connection_remove(conn);
+ return;
+ }
+ if (res == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No more data available over TCP");
+ dpp_connection_remove(conn);
+ return;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received %d/%d octet(s) of message length field",
+ res, (int) (4 - conn->msg_len_octets));
+ conn->msg_len_octets += res;
+
+ if (conn->msg_len_octets < 4) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Need %d more octets of message length field",
+ (int) (4 - conn->msg_len_octets));
+ return;
+ }
+
+ msglen = WPA_GET_BE32(conn->msg_len);
+ wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
+ if (msglen > 65535) {
+ wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ wpabuf_free(conn->msg);
+ conn->msg = wpabuf_alloc(msglen);
+ }
+
+ if (!conn->msg) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No buffer available for receiving the message");
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
+ (unsigned int) wpabuf_tailroom(conn->msg));
+
+ res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
+ dpp_connection_remove(conn);
+ return;
+ }
+ if (res == 0) {
+ wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
+ dpp_connection_remove(conn);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
+ wpabuf_put(conn->msg, res);
+
+ if (wpabuf_tailroom(conn->msg) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Need %u more octets of message payload",
+ (unsigned int) wpabuf_tailroom(conn->msg));
+ return;
+ }
+
+ conn->msg_len_octets = 0;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
+ if (wpabuf_len(conn->msg) < 1) {
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ pos = wpabuf_head(conn->msg);
+ switch (*pos) {
+ case WLAN_PA_VENDOR_SPECIFIC:
+ if (dpp_controller_rx_action(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_INITIAL_REQ:
+ if (dpp_controller_rx_gas_req(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_INITIAL_RESP:
+ case WLAN_PA_GAS_COMEBACK_RESP:
+ if (dpp_rx_gas_resp(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1,
+ *pos == WLAN_PA_GAS_COMEBACK_RESP) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_COMEBACK_REQ:
+ if (dpp_controller_rx_gas_comeback_req(
+ conn, pos + 1, wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
+ *pos);
+ break;
+ }
+}
+
+
+static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_controller *ctrl = eloop_ctx;
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ int fd;
+ struct dpp_connection *conn;
+
+ wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
+
+ fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
+ if (fd < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to accept new connection: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ goto fail;
+
+ conn->global = ctrl->global;
+ conn->ctrl = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->cb_ctx;
+ conn->process_conf_obj = ctrl->process_conf_obj;
+ conn->sock = fd;
+ conn->netrole = ctrl->netrole;
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
+ dpp_controller_rx, conn, NULL) < 0)
+ goto fail;
+ conn->read_eloop = 1;
+
+ /* TODO: eloop timeout to expire connections that do not complete in
+ * reasonable time */
+ dl_list_add(&ctrl->conn, &conn->list);
+ return;
+
+fail:
+ close(fd);
+ os_free(conn);
+}
+
+
+int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ const struct hostapd_ip_addr *addr, int port, const char *name,
+ enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth))
+{
+ struct dpp_connection *conn;
+ struct sockaddr_storage saddr;
+ socklen_t addrlen;
+ const u8 *hdr, *pos, *end;
+ char txt[100];
+
+ wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
+ hostapd_ip_txt(addr, txt, sizeof(txt)), port);
+ if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
+ addr, port) < 0) {
+ dpp_auth_deinit(auth);
+ return -1;
+ }
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn) {
+ dpp_auth_deinit(auth);
+ return -1;
+ }
+
+ conn->msg_ctx = msg_ctx;
+ conn->cb_ctx = cb_ctx;
+ conn->process_conf_obj = process_conf_obj;
+ conn->name = os_strdup(name ? name : "Test");
+ conn->netrole = netrole;
+ conn->global = dpp;
+ conn->auth = auth;
+ conn->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (conn->sock < 0)
+ goto fail;
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
+ if (errno != EINPROGRESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /*
+ * Continue connecting in the background; eloop will call us
+ * once the connection is ready (or failed).
+ */
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) < 0)
+ goto fail;
+ conn->write_eloop = 1;
+
+ hdr = wpabuf_head(auth->req_msg);
+ end = hdr + wpabuf_len(auth->req_msg);
+ hdr += 2; /* skip Category and Actiom */
+ pos = hdr + DPP_HDR_LEN;
+ conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
+ if (!conn->msg_out)
+ goto fail;
+ /* Message will be sent in dpp_conn_tx_ready() */
+
+ /* TODO: eloop timeout to clear a connection if it does not complete
+ * properly */
+ dl_list_add(&dpp->tcp_init, &conn->list);
+ return 0;
+fail:
+ dpp_connection_free(conn);
+ return -1;
+}
+
+
+int dpp_controller_start(struct dpp_global *dpp,
+ struct dpp_controller_config *config)
+{
+ struct dpp_controller *ctrl;
+ int on = 1;
+ struct sockaddr_in sin;
+ int port;
+
+ if (!dpp || dpp->controller)
+ return -1;
+
+ ctrl = os_zalloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -1;
+ ctrl->global = dpp;
+ if (config->configurator_params)
+ ctrl->configurator_params =
+ os_strdup(config->configurator_params);
+ dl_list_init(&ctrl->conn);
+ ctrl->allowed_roles = config->allowed_roles;
+ ctrl->qr_mutual = config->qr_mutual;
+ ctrl->netrole = config->netrole;
+ ctrl->msg_ctx = config->msg_ctx;
+ ctrl->cb_ctx = config->cb_ctx;
+ ctrl->process_conf_obj = config->process_conf_obj;
+
+ ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctrl->sock < 0)
+ goto fail;
+
+ if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: setsockopt(SO_REUSEADDR) failed: %s",
+ strerror(errno));
+ /* try to continue anyway */
+ }
+
+ if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
+ wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /* TODO: IPv6 */
+ os_memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
+ sin.sin_port = htons(port);
+ if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to bind Controller TCP port: %s",
+ strerror(errno));
+ goto fail;
+ }
+ if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
+ fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
+ eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
+ dpp_controller_tcp_cb, ctrl, NULL))
+ goto fail;
+
+ dpp->controller = ctrl;
+ wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
+ return 0;
+fail:
+ dpp_controller_free(ctrl);
+ return -1;
+}
+
+
+void dpp_controller_stop(struct dpp_global *dpp)
+{
+ if (dpp) {
+ dpp_controller_free(dpp->controller);
+ dpp->controller = NULL;
+ }
+}
+
+
+static bool dpp_tcp_peer_id_match(struct dpp_authentication *auth,
+ unsigned int id)
+{
+ return auth &&
+ ((auth->peer_bi && auth->peer_bi->id == id) ||
+ (auth->tmp_peer_bi && auth->tmp_peer_bi->id == id));
+}
+
+
+static struct dpp_authentication * dpp_tcp_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_connection *conn;
+
+ dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return NULL;
+}
+
+
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return dpp_tcp_get_auth(dpp, id);
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return dpp_tcp_get_auth(dpp, id);
+}
+
+
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return;
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth->response_pending ||
+ dpp_notify_new_qr_code(auth, bi) != 1)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending out pending authentication response");
+ dpp_tcp_send_msg(conn, conn->auth->resp_msg);
+ }
+}
+
+
+void dpp_tcp_init_flush(struct dpp_global *dpp)
+{
+ struct dpp_connection *conn, *tmp;
+
+ dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+}
+
+
+static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
+{
+ struct dpp_connection *conn, *tmp;
+
+ dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+ os_free(ctrl);
+}
+
+
+void dpp_relay_flush_controllers(struct dpp_global *dpp)
+{
+ struct dpp_relay_controller *ctrl, *tmp;
+
+ if (!dpp)
+ return;
+
+ dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ dl_list_del(&ctrl->list);
+ dpp_relay_controller_free(ctrl);
+ }
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/common/gas_server.c b/contrib/wpa/src/common/gas_server.c
index ca46758cec7c..5f44ffebdea0 100644
--- a/contrib/wpa/src/common/gas_server.c
+++ b/contrib/wpa/src/common/gas_server.c
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,8 +24,9 @@ struct gas_server_handler {
struct dl_list list;
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
u8 adv_proto_id_len;
- struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len);
+ struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay);
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
void *ctx;
struct gas_server *gas;
@@ -39,6 +41,7 @@ struct gas_server_response {
u8 dst[ETH_ALEN];
u8 dialog_token;
struct gas_server_handler *handler;
+ u16 comeback_delay;
};
struct gas_server {
@@ -61,7 +64,8 @@ static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
response, MAC2STR(response->dst), response->dialog_token,
response->freq, response->frag_id,
(unsigned long) response->offset,
- (unsigned long) wpabuf_len(response->resp));
+ (unsigned long) (response->resp ?
+ wpabuf_len(response->resp) : 0));
response->handler->status_cb(response->handler->ctx,
response->resp, 0);
response->resp = NULL;
@@ -83,30 +87,29 @@ static void gas_server_free_response(struct gas_server_response *response)
static void
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
+ struct gas_server_response *response,
const u8 *da, int freq, u8 dialog_token,
- struct wpabuf *query_resp)
+ struct wpabuf *query_resp, u16 comeback_delay)
{
size_t max_len = (freq > 56160) ? 928 : 1400;
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
size_t resp_frag_len;
struct wpabuf *resp;
- u16 comeback_delay;
- struct gas_server_response *response;
- if (!query_resp)
- return;
-
- response = os_zalloc(sizeof(*response));
- if (!response) {
- wpabuf_free(query_resp);
+ if (comeback_delay == 0 && !query_resp) {
+ gas_server_free_response(response);
return;
}
- wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
+
response->freq = freq;
response->handler = handler;
os_memcpy(response->dst, da, ETH_ALEN);
response->dialog_token = dialog_token;
- if (hdr_len + wpabuf_len(query_resp) > max_len) {
+ if (comeback_delay) {
+ /* Need more time to prepare the response */
+ resp_frag_len = 0;
+ response->comeback_delay = comeback_delay;
+ } else if (hdr_len + wpabuf_len(query_resp) > max_len) {
/* Need to use comeback to initiate fragmentation */
comeback_delay = 1;
resp_frag_len = 0;
@@ -135,10 +138,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
/* Query Response Length */
wpabuf_put_le16(resp, resp_frag_len);
- if (!comeback_delay)
+ if (!comeback_delay && query_resp)
wpabuf_put_buf(resp, query_resp);
- if (comeback_delay) {
+ if (comeback_delay && !query_resp) {
+ wpa_printf(MSG_DEBUG, "GAS: No response available yet");
+ } else if (comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Need to fragment query response");
} else {
@@ -165,6 +170,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
u16 query_req_len;
struct gas_server_handler *handler;
struct wpabuf *resp;
+ struct gas_server_response *response;
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
data, len);
@@ -210,8 +216,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
pos, end - pos);
}
+ response = os_zalloc(sizeof(*response));
+ if (!response)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
list) {
+ u16 comeback_delay = 0;
+
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
handler->adv_proto_id_len) != 0)
@@ -219,17 +232,22 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
wpa_printf(MSG_DEBUG,
"GAS: Calling handler for the requested Advertisement Protocol ID");
- resp = handler->req_cb(handler->ctx, sa, query_req,
- query_req_len);
+ resp = handler->req_cb(handler->ctx, response, sa, query_req,
+ query_req_len, &comeback_delay);
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
resp);
- gas_server_send_resp(gas, handler, sa, freq, dialog_token,
- resp);
+ if (comeback_delay)
+ wpa_printf(MSG_DEBUG,
+ "GAS: Handler requested comeback delay: %u TU",
+ comeback_delay);
+ gas_server_send_resp(gas, handler, response, sa, freq,
+ dialog_token, resp, comeback_delay);
return 0;
}
wpa_printf(MSG_DEBUG,
"GAS: No registered handler for the requested Advertisement Protocol ID");
+ gas_server_free_response(response);
return -1;
}
@@ -243,6 +261,31 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
size_t remaining, resp_frag_len;
struct wpabuf *resp;
+ unsigned int wait_time = 0;
+
+ if (!response->resp) {
+ resp = gas_build_comeback_resp(response->dialog_token,
+ WLAN_STATUS_SUCCESS, 0, 0,
+ response->comeback_delay,
+ handler->adv_proto_id_len);
+ if (!resp) {
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+ return;
+ }
+
+ /* Advertisement Protocol element */
+ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
+ wpabuf_put_u8(resp, 0x7f);
+ /* Advertisement Protocol ID */
+ wpabuf_put_data(resp, handler->adv_proto_id,
+ handler->adv_proto_id_len);
+
+ /* Query Response Length */
+ wpabuf_put_le16(resp, 0);
+ goto send_resp;
+ }
remaining = wpabuf_len(response->resp) - response->offset;
if (hdr_len + remaining > max_len)
@@ -279,8 +322,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
response->offset += resp_frag_len;
- gas->tx(gas->ctx, response->freq, response->dst, resp,
- remaining > resp_frag_len ? 2000 : 0);
+ if (remaining > resp_frag_len)
+ wait_time = 2000;
+
+send_resp:
+ gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
wpabuf_free(resp);
}
@@ -359,12 +405,19 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack)
{
- if (ack && response->offset < wpabuf_len(response->resp)) {
+ if (ack && response->resp &&
+ response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG,
"GAS: More fragments remaining - keep pending entry");
return;
}
+ if (ack && !response->resp && response->comeback_delay) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Waiting for response - keep pending entry");
+ return;
+ }
+
if (!ack)
wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry");
@@ -415,6 +468,42 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
}
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp)
+{
+ struct gas_server_response *tmp, *response = NULL;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx) {
+ response = tmp;
+ break;
+ }
+ }
+
+ if (!response || response->resp)
+ return -1;
+
+ response->resp = resp;
+ return 0;
+}
+
+
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
+{
+ struct gas_server_response *tmp;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx)
+ return tmp->resp &&
+ tmp->offset == wpabuf_len(tmp->resp);
+ }
+
+ return false;
+}
+
+
struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq,
const u8 *da,
@@ -461,8 +550,9 @@ void gas_server_deinit(struct gas_server *gas)
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx)
diff --git a/contrib/wpa/src/common/gas_server.h b/contrib/wpa/src/common/gas_server.h
index 299f529f7c56..db00f87e8de1 100644
--- a/contrib/wpa/src/common/gas_server.h
+++ b/contrib/wpa/src/common/gas_server.h
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,8 +23,9 @@ void gas_server_deinit(struct gas_server *gas);
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx);
@@ -32,6 +34,9 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
int freq);
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
size_t data_len, int ack);
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp);
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
#else /* CONFIG_GAS_SERVER */
diff --git a/contrib/wpa/src/common/hw_features_common.c b/contrib/wpa/src/common/hw_features_common.c
index 3fdbf893d2b7..ad2aebfef5b5 100644
--- a/contrib/wpa/src/common/hw_features_common.c
+++ b/contrib/wpa/src/common/hw_features_common.c
@@ -40,19 +40,14 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
}
-struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
- int freq, int *chan)
+struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
{
int i;
- if (chan)
- *chan = 0;
-
- if (!mode)
- return NULL;
-
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *ch = &mode->channels[i];
+
if (ch->freq == freq) {
if (chan)
*chan = ch->chan;
@@ -64,6 +59,34 @@ struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
}
+struct hostapd_channel_data *
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
+ struct hostapd_hw_modes *hw_features, int num_hw_features)
+{
+ struct hostapd_channel_data *chan_data;
+ int i;
+
+ if (chan)
+ *chan = 0;
+
+ if (!hw_features)
+ return NULL;
+
+ for (i = 0; i < num_hw_features; i++) {
+ struct hostapd_hw_modes *curr_mode = &hw_features[i];
+
+ if (curr_mode->mode != mode)
+ continue;
+
+ chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+ if (chan_data)
+ return chan_data;
+ }
+
+ return NULL;
+}
+
+
int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
{
int freq;
@@ -74,29 +97,33 @@ int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
}
-int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+ struct hostapd_hw_modes *hw_features, int num_hw_features)
{
int chan;
- hw_get_channel_freq(mode, freq, &chan);
+ hw_get_channel_freq(mode, freq, &chan, hw_features, num_hw_features);
return chan;
}
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan)
+int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
+ struct hostapd_channel_data *p_chan,
+ struct hostapd_channel_data *s_chan)
{
int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
149, 157, 165, 184, 192 };
size_t k;
- struct hostapd_channel_data *p_chan, *s_chan;
- const int ht40_plus = pri_chan < sec_chan;
+ int ht40_plus, pri_chan, sec_chan;
- p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
- if (!p_chan)
+ if (!p_chan || !s_chan)
return 0;
+ pri_chan = p_chan->chan;
+ sec_chan = s_chan->chan;
+
+ ht40_plus = pri_chan < sec_chan;
if (pri_chan == sec_chan || !sec_chan) {
if (chan_pri_allowed(p_chan))
@@ -107,13 +134,9 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
return 0;
}
- s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
- if (!s_chan)
- return 0;
-
wpa_printf(MSG_DEBUG,
- "HT40: control channel: %d secondary channel: %d",
- pri_chan, sec_chan);
+ "HT40: control channel: %d (%d MHz), secondary channel: %d (%d MHz)",
+ pri_chan, p_chan->freq, sec_chan, s_chan->freq);
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
@@ -131,7 +154,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
* 2.4 GHz rules allow all cases where the secondary channel fits into
* the list of allowed channels (already checked above).
*/
- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ if (mode != HOSTAPD_MODE_IEEE80211A)
return 1;
first = pri_chan < sec_chan ? pri_chan : sec_chan;
@@ -176,22 +199,19 @@ 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_40mhz_5g(struct wpa_scan_results *scan_res,
+ struct hostapd_channel_data *pri_chan,
+ struct hostapd_channel_data *sec_chan)
{
- int pri_freq, sec_freq, pri_bss, sec_bss;
+ int pri_bss, sec_bss;
int bss_pri_chan, bss_sec_chan;
size_t i;
int match;
- if (!mode || !scan_res || !pri_chan || !sec_chan ||
- pri_chan == sec_chan)
+ if (!scan_res || !pri_chan || !sec_chan ||
+ pri_chan->freq == sec_chan->freq)
return 0;
- pri_freq = hw_get_freq(mode, pri_chan);
- sec_freq = hw_get_freq(mode, sec_chan);
-
/*
* Switch PRI/SEC channels if Beacons were detected on selected SEC
* channel, but not on selected PRI channel.
@@ -199,9 +219,9 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
pri_bss = sec_bss = 0;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
- if (bss->freq == pri_freq)
+ if (bss->freq == pri_chan->freq)
pri_bss++;
- else if (bss->freq == sec_freq)
+ else if (bss->freq == sec_chan->freq)
sec_bss++;
}
if (sec_bss && !pri_bss) {
@@ -219,8 +239,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_pri_chan &&
- sec_chan == bss_sec_chan) {
+ if (pri_chan->chan == bss_pri_chan &&
+ sec_chan->chan == bss_sec_chan) {
match = 1;
break;
}
@@ -229,8 +249,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_sec_chan &&
- sec_chan == bss_pri_chan) {
+ if (pri_chan->chan == bss_sec_chan &&
+ sec_chan->chan == bss_pri_chan) {
wpa_printf(MSG_INFO, "Switch own primary and "
"secondary channel due to BSS "
"overlap with " MACSTR,
@@ -273,12 +293,87 @@ static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
}
+/*
+ * Returns:
+ * 0: no impact
+ * 1: overlapping BSS
+ * 2: overlapping BSS with 40 MHz intolerant advertisement
+ */
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq)
+{
+ int affected_start, affected_end;
+ struct ieee802_11_elems elems;
+ int pri_chan, sec_chan;
+ int pri = bss->freq;
+ int sec = pri;
+
+ if (pri_freq == sec_freq)
+ return 1;
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+
+ /* Check for overlapping 20 MHz BSS */
+ if (check_20mhz_bss(bss, pri_freq, affected_start, affected_end)) {
+ wpa_printf(MSG_DEBUG, "Overlapping 20 MHz BSS is found");
+ return 1;
+ }
+
+ get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+ if (sec_chan) {
+ if (sec_chan < pri_chan)
+ sec = pri - 20;
+ else
+ sec = pri + 20;
+ }
+
+ if ((pri < affected_start || pri > affected_end) &&
+ (sec < affected_start || sec > affected_end))
+ return 0; /* not within affected channel range */
+
+ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+ " freq=%d pri=%d sec=%d",
+ MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+ if (sec_chan) {
+ if (pri_freq != pri || sec_freq != sec) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz pri/sec mismatch with BSS "
+ MACSTR
+ " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+ MAC2STR(bss->bssid),
+ pri, sec, pri_chan,
+ sec > pri ? '+' : '-',
+ pri_freq, sec_freq);
+ return 1;
+ }
+ }
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (elems.ht_capabilities) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan)
{
int pri_freq, sec_freq;
- int affected_start, affected_end;
size_t i;
if (!mode || !scan_res || !pri_chan || !sec_chan ||
@@ -288,70 +383,12 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
pri_freq = hw_get_freq(mode, pri_chan);
sec_freq = hw_get_freq(mode, sec_chan);
- affected_start = (pri_freq + sec_freq) / 2 - 25;
- affected_end = (pri_freq + sec_freq) / 2 + 25;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
- affected_start, affected_end);
+ (pri_freq + sec_freq) / 2 - 25,
+ (pri_freq + sec_freq) / 2 + 25);
for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- int pri = bss->freq;
- int sec = pri;
- struct ieee802_11_elems elems;
-
- /* Check for overlapping 20 MHz BSS */
- if (check_20mhz_bss(bss, pri_freq, affected_start,
- affected_end)) {
- wpa_printf(MSG_DEBUG,
- "Overlapping 20 MHz BSS is found");
+ if (check_bss_coex_40mhz(scan_res->res[i], pri_freq, sec_freq))
return 0;
- }
-
- get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
- if (sec_chan) {
- if (sec_chan < pri_chan)
- sec = pri - 20;
- else
- sec = pri + 20;
- }
-
- if ((pri < affected_start || pri > affected_end) &&
- (sec < affected_start || sec > affected_end))
- continue; /* not within affected channel range */
-
- wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
- " freq=%d pri=%d sec=%d",
- MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
- if (sec_chan) {
- if (pri_freq != pri || sec_freq != sec) {
- wpa_printf(MSG_DEBUG,
- "40 MHz pri/sec mismatch with BSS "
- MACSTR
- " <%d,%d> (chan=%d%c) vs. <%d,%d>",
- MAC2STR(bss->bssid),
- pri, sec, pri_chan,
- sec > pri ? '+' : '-',
- pri_freq, sec_freq);
- return 0;
- }
- }
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
- 0);
- if (elems.ht_capabilities) {
- struct ieee80211_ht_capabilities *ht_cap =
- (struct ieee80211_ht_capabilities *)
- elems.ht_capabilities;
-
- if (le_to_host16(ht_cap->ht_capabilities_info) &
- HT_CAP_INFO_40MHZ_INTOLERANT) {
- wpa_printf(MSG_DEBUG,
- "40 MHz Intolerant is set on channel %d in BSS "
- MACSTR, pri, MAC2STR(bss->bssid));
- return 0;
- }
- }
}
return 1;
@@ -360,7 +397,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ int freq, int channel, int enable_edmg,
+ u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
@@ -381,13 +419,116 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
data->center_freq2 = 0;
data->bandwidth = sec_channel_offset ? 40 : 20;
- if (data->vht_enabled) switch (oper_chwidth) {
+ hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
+ &data->edmg);
+
+ if (is_6ghz_freq(freq)) {
+ if (!data->he_enabled) {
+ wpa_printf(MSG_ERROR,
+ "Can't set 6 GHz mode - HE isn't enabled");
+ return -1;
+ }
+
+ if (center_idx_to_bw_6ghz(channel) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid control channel for 6 GHz band");
+ return -1;
+ }
+
+ if (!center_segment0) {
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "Segment 0 center frequency isn't set");
+ return -1;
+ }
+
+ data->center_freq1 = data->freq;
+ data->bandwidth = 20;
+ } else {
+ int freq1, freq2 = 0;
+ int bw = center_idx_to_bw_6ghz(center_segment0);
+
+ if (bw < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid center frequency index for 6 GHz");
+ return -1;
+ }
+
+ freq1 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment0);
+ if (freq1 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 0 center frequency for 6 GHz");
+ return -1;
+ }
+
+ if (center_segment1) {
+ if (center_idx_to_bw_6ghz(center_segment1) != 2 ||
+ bw != 2) {
+ wpa_printf(MSG_ERROR,
+ "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels");
+ return -1;
+ }
+
+ freq2 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment1);
+ if (freq2 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 1 center frequency for UHB");
+ return -1;
+ }
+ }
+
+ data->bandwidth = (1 << (u8) bw) * 20;
+ data->center_freq1 = freq1;
+ data->center_freq2 = freq2;
+ }
+ data->ht_enabled = 0;
+ data->vht_enabled = 0;
+
+ return 0;
+ }
+
+ if (data->he_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
- if (center_segment1 ||
- (center_segment0 != 0 &&
- 5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1))
+ if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_ERROR,
+ "40 MHz channel width is not supported in 2.4 GHz");
+ return -1;
+ }
+ break;
+ }
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ if (mode == HOSTAPD_MODE_IEEE80211A) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "40/80 MHz channel width is not supported in 5/6 GHz");
+ return -1;
+ }
+ }
+ break;
+ case CHANWIDTH_80P80MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz channel width is not supported in 5/6 GHz");
+ return -1;
+ }
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported in 5 / 6GHz");
return -1;
+ }
+ break;
+ } else if (data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
break;
case CHANWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
@@ -395,19 +536,57 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
"80+80 channel width is not supported!");
return -1;
}
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported!");
+ return -1;
+ }
+ break;
+ }
+
+ if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ if (center_segment1 ||
+ (center_segment0 != 0 &&
+ 5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1)) {
+ wpa_printf(MSG_ERROR,
+ "20/40 MHz: center segment 0 (=%d) and center freq 1 (=%d) not in sync",
+ center_segment0, data->center_freq1);
+ return -1;
+ }
+ break;
+ case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
- center_segment1 == center_segment0 - 4)
+ center_segment1 == center_segment0 - 4) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz: center segment 1 only 20 MHz apart");
return -1;
+ }
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
case CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if ((oper_chwidth == CHANWIDTH_80MHZ &&
- center_segment1) ||
- (oper_chwidth == CHANWIDTH_80P80MHZ &&
- !center_segment1) ||
- !sec_channel_offset)
+ if (!sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "80/80+80 MHz: no second channel offset");
+ return -1;
+ }
+ if (oper_chwidth == CHANWIDTH_80MHZ && center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "80 MHz: center segment 1 configured");
+ return -1;
+ }
+ if (oper_chwidth == CHANWIDTH_80P80MHZ && !center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz: center segment 1 not configured");
return -1;
+ }
if (!center_segment0) {
if (channel <= 48)
center_segment0 = 42;
@@ -421,6 +600,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 = 138;
else if (channel <= 161)
center_segment0 = 155;
+ else if (channel <= 177)
+ center_segment0 = 171;
data->center_freq1 = 5000 + center_segment0 * 5;
} else {
/*
@@ -433,22 +614,25 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 2 ||
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "Wrong coupling between HT and VHT/HE channel setting");
return -1;
+ }
}
break;
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
- if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ if (center_segment1) {
wpa_printf(MSG_ERROR,
- "160MHZ channel width is not supported!");
+ "160 MHz: center segment 1 should not be set");
return -1;
}
- if (center_segment1)
- return -1;
- if (!sec_channel_offset)
+ if (!sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: second channel offset not set");
return -1;
+ }
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration.
@@ -462,8 +646,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 10 ||
center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: HT40 channel band is not in 160 MHz band");
return -1;
+ }
break;
}
diff --git a/contrib/wpa/src/common/hw_features_common.h b/contrib/wpa/src/common/hw_features_common.h
index 2d2a539943c0..ddde36b99263 100644
--- a/contrib/wpa/src/common/hw_features_common.h
+++ b/contrib/wpa/src/common/hw_features_common.h
@@ -14,24 +14,32 @@
struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
int chan, int *freq);
-struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
- int freq, int *chan);
+struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+
+struct hostapd_channel_data *
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
+ struct hostapd_hw_modes *hw_features, int num_hw_features);
int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
-int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
+int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+ struct hostapd_hw_modes *hw_features, int num_hw_features);
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan);
+int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
+ struct hostapd_channel_data *p_chan,
+ struct hostapd_channel_data *s_chan);
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_40mhz_5g(struct wpa_scan_results *scan_res,
+ struct hostapd_channel_data *pri_chan,
+ struct hostapd_channel_data *sec_chan);
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq);
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled,
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
diff --git a/contrib/wpa/src/common/ieee802_11_common.c b/contrib/wpa/src/common/ieee802_11_common.c
index a081f87cc2a7..3e5cfb01d565 100644
--- a/contrib/wpa/src/common/ieee802_11_common.c
+++ b/contrib/wpa/src/common/ieee802_11_common.c
@@ -130,6 +130,16 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->multi_ap = pos;
elems->multi_ap_len = elen;
break;
+ case OWE_OUI_TYPE:
+ /* OWE Transition Mode element */
+ break;
+ case DPP_CC_OUI_TYPE:
+ /* DPP Configurator Connectivity element */
+ break;
+ case SAE_PK_OUI_TYPE:
+ elems->sae_pk = pos + 4;
+ elems->sae_pk_len = elen - 4;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -206,6 +216,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
ext_id = *pos++;
elen--;
+ elems->frag_ies.last_eid_ext = 0;
+
switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1)
@@ -245,9 +257,9 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->key_delivery = pos;
elems->key_delivery_len = elen;
break;
- case WLAN_EID_EXT_FILS_WRAPPED_DATA:
- elems->fils_wrapped_data = pos;
- elems->fils_wrapped_data_len = elen;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ elems->wrapped_data = pos;
+ elems->wrapped_data_len = elen;
break;
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
if (elen < 1)
@@ -282,6 +294,19 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->oci = pos;
elems->oci_len = elen;
break;
+ case WLAN_EID_EXT_SHORT_SSID_LIST:
+ elems->short_ssid_list = pos;
+ elems->short_ssid_list_len = elen;
+ break;
+ case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
+ if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
+ break;
+ elems->he_6ghz_band_cap = pos;
+ break;
+ case WLAN_EID_EXT_PASN_PARAMS:
+ elems->pasn_params = pos;
+ elems->pasn_params_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -291,10 +316,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
return -1;
}
+ if (elen == 254)
+ elems->frag_ies.last_eid_ext = ext_id;
+
return 0;
}
+static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
+ const u8 *pos, u8 elen)
+{
+ if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
+ wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
+ return;
+ }
+
+ /*
+ * Note: while EID == 0 is a valid ID (SSID IE), it should not be
+ * fragmented.
+ */
+ if (!frag_ies->last_eid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Fragment without a valid last element - skip");
+ return;
+ }
+
+ frag_ies->frags[frag_ies->n_frags].ie = pos;
+ frag_ies->frags[frag_ies->n_frags].ie_len = elen;
+ frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
+ frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
+ frag_ies->n_frags++;
+}
+
+
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@@ -327,6 +381,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elen);
break;
}
+ if (elems->ssid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Ignored duplicated SSID element");
+ break;
+ }
elems->ssid = pos;
elems->ssid_len = elen;
break;
@@ -365,6 +424,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
+ case WLAN_EID_RSNX:
+ elems->rsnxe = pos;
+ elems->rsnxe_len = elen;
+ break;
case WLAN_EID_PWR_CAPABILITY:
if (elen < 2)
break;
@@ -507,8 +570,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils = pos;
elems->dils_len = elen;
break;
+ case WLAN_EID_S1G_CAPABILITIES:
+ if (elen < 15)
+ break;
+ elems->s1g_capab = pos;
+ break;
case WLAN_EID_FRAGMENT:
- /* TODO */
+ ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems,
@@ -524,6 +592,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
id, elen);
break;
}
+
+ if (id != WLAN_EID_FRAGMENT && elen == 255)
+ elems->frag_ies.last_eid = id;
+
+ if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
+ elems->frag_ies.last_eid = 0;
}
if (!for_each_element_completed(elem, start, len)) {
@@ -702,6 +776,98 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
}
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15
+ */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = os_strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
+ cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
+ cw == 32767);
+}
+
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
+ const char *name, const char *val)
+{
+ int num;
+ const char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (os_strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+ os_strncmp(pos, "beacon_", 7) == 0) {
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+ return -1;
+ }
+
+ if (num >= NUM_TX_QUEUES) {
+ /* for backwards compatibility, do not trigger failure */
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ }
+
+ queue = &tx_queue[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+ queue->aifs);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+ queue->cwmin);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+ queue->cwmax);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
@@ -713,16 +879,17 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
/**
* ieee80211_freq_to_channel_ext - Convert frequency into channel info
- * for HT40 and VHT. DFS channels are not covered.
+ * for HT40, VHT, and HE. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @vht: VHT channel width (CHANWIDTH_*)
+ * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
* @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,
+ int sec_channel,
+ int chanwidth,
u8 *op_class, u8 *channel)
{
u8 vht_opclass;
@@ -736,7 +903,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
if ((freq - 2407) % 5)
return NUM_HOSTAPD_MODES;
- if (vht)
+ if (chanwidth)
return NUM_HOSTAPD_MODES;
/* 2.407 GHz, channels 1..13 */
@@ -753,7 +920,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
}
if (freq == 2484) {
- if (sec_channel || vht)
+ if (sec_channel || chanwidth)
return NUM_HOSTAPD_MODES;
*op_class = 82; /* channel 14 */
@@ -770,7 +937,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- switch (vht) {
+ switch (chanwidth) {
case CHANWIDTH_80MHZ:
vht_opclass = 128;
break;
@@ -823,8 +990,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 5 GHz, channels 149..169 */
- if (freq >= 5745 && freq <= 5845) {
+ /* 5 GHz, channels 149..177 */
+ if (freq >= 5745 && freq <= 5885) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
@@ -871,13 +1038,76 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 56.16 GHz, channel 1..4 */
- if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
- if (sec_channel || vht)
+ if (freq > 5950 && freq <= 7115) {
+ if ((freq - 5950) % 5)
return NUM_HOSTAPD_MODES;
- *channel = (freq - 56160) / 2160;
- *op_class = 180;
+ switch (chanwidth) {
+ case CHANWIDTH_80MHZ:
+ *op_class = 133;
+ break;
+ case CHANWIDTH_160MHZ:
+ *op_class = 134;
+ break;
+ case CHANWIDTH_80P80MHZ:
+ *op_class = 135;
+ break;
+ default:
+ if (sec_channel)
+ *op_class = 132;
+ else
+ *op_class = 131;
+ break;
+ }
+
+ *channel = (freq - 5950) / 5;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ if (freq == 5935) {
+ *op_class = 136;
+ *channel = (freq - 5925) / 5;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 56.16 GHz, channel 1..6 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
+ if (sec_channel)
+ return NUM_HOSTAPD_MODES;
+
+ switch (chanwidth) {
+ case CHANWIDTH_USE_HT:
+ case CHANWIDTH_2160MHZ:
+ *channel = (freq - 56160) / 2160;
+ *op_class = 180;
+ break;
+ case CHANWIDTH_4320MHZ:
+ /* EDMG channels 9 - 13 */
+ if (freq > 56160 + 2160 * 5)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 8;
+ *op_class = 181;
+ break;
+ case CHANWIDTH_6480MHZ:
+ /* EDMG channels 17 - 20 */
+ if (freq > 56160 + 2160 * 4)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 16;
+ *op_class = 182;
+ break;
+ case CHANWIDTH_8640MHZ:
+ /* EDMG channels 25 - 27 */
+ if (freq > 56160 + 2160 * 3)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 24;
+ *op_class = 183;
+ break;
+ default:
+ return NUM_HOSTAPD_MODES;
+ }
return HOSTAPD_MODE_IEEE80211AD;
}
@@ -889,27 +1119,39 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
int sec_channel, u8 *op_class, u8 *channel)
{
- int vht = CHAN_WIDTH_UNKNOWN;
+ int cw = CHAN_WIDTH_UNKNOWN;
switch (chanwidth) {
case CHAN_WIDTH_UNKNOWN:
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
- vht = CHANWIDTH_USE_HT;
+ cw = CHANWIDTH_USE_HT;
break;
case CHAN_WIDTH_80:
- vht = CHANWIDTH_80MHZ;
+ cw = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- vht = CHANWIDTH_80P80MHZ;
+ cw = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- vht = CHANWIDTH_160MHZ;
+ cw = CHANWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_2160:
+ cw = CHANWIDTH_2160MHZ;
+ break;
+ case CHAN_WIDTH_4320:
+ cw = CHANWIDTH_4320MHZ;
+ break;
+ case CHAN_WIDTH_6480:
+ cw = CHANWIDTH_6480MHZ;
+ break;
+ case CHAN_WIDTH_8640:
+ cw = CHANWIDTH_8640MHZ;
break;
}
- if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
+ if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
channel) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_WARNING,
"Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
@@ -991,10 +1233,22 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
if (chan < 149 || chan > 165)
return -1;
return 5000 + 5 * chan;
- case 34: /* 60 GHz band, channels 1..3 */
- if (chan < 1 || chan > 3)
+ case 34: /* 60 GHz band, channels 1..8 */
+ if (chan < 1 || chan > 8)
return -1;
return 56160 + 2160 * chan;
+ case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ if (chan < 9 || chan > 15)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ if (chan < 17 || chan > 22)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
+ if (chan < 25 || chan > 29)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1029,10 +1283,22 @@ static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
if (chan < 149 || chan > 169)
return -1;
return 5000 + 5 * chan;
- case 18: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 18: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
+ case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
+ if (chan < 9 || chan > 11)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
+ if (chan < 17 || chan > 18)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 23: /* 60 GHz band, EDMG CB4, channels 25 */
+ if (chan != 25)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1073,10 +1339,22 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
if (chan < 100 || chan > 140)
return -1;
return 5000 + 5 * chan;
- case 59: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 3)
+ case 59: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
+ case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
+ if (chan < 9 || chan > 11)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
+ if (chan < 17 || chan > 18)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 64: /* 60 GHz band, EDMG CB4, channel 25 */
+ if (chan != 25)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1143,28 +1421,52 @@ 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 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)
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
+ case 126: /* channels 149,157,165,173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
+ if (chan < 149 || chan > 177)
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)
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 129: /* center freqs 50, 114; 160 MHz */
- if (chan < 36 || chan > 128)
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 180: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ if (chan < 1 || chan > 233)
+ return -1;
+ return 5950 + chan * 5;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ if (chan == 2)
+ return 5935;
+ return -1;
+ case 180: /* 60 GHz band, channels 1..8 */
+ if (chan < 1 || chan > 8)
return -1;
return 56160 + 2160 * chan;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ if (chan < 9 || chan > 15)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ if (chan < 17 || chan > 22)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ if (chan < 25 || chan > 29)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1492,6 +1794,9 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(DENIED_HE_NOT_SUPPORTED)
+ S2S(SAE_HASH_TO_ELEMENT)
+ S2S(SAE_PK)
}
return "UNKNOWN";
#undef S2S
@@ -1575,22 +1880,42 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
/*
- * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
- * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
- * 80 MHz, but currently use the following definition for simplicity
+ * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center
+ * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing
+ * of 80 MHz, but currently use the following definition for simplicity
* (these center frequencies are not actual channels, which makes
- * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
+ * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take
* care of removing invalid channels.
*/
- { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
+
+ /*
+ * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
+ * Class 180 has the legacy channels 1-6. Classes 181-183 include
+ * channels which implement channel bonding features.
+ */
+ { HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
+
+ /* Keep the operating class 130 as the last entry as a workaround for
+ * the OneHundredAndThirty Delimiter value used in the Supported
+ * Operating Classes element to indicate the end of the Operating
+ * Classes field. */
+ { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -1888,6 +2213,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
switch (map->bw) {
case BW20:
return 20;
+ case BW40:
case BW40PLUS:
case BW40MINUS:
return 40;
@@ -1904,6 +2230,69 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
}
+int center_idx_to_bw_6ghz(u8 idx)
+{
+ /* Channel: 2 */
+ if (idx == 2)
+ return 0; /* 20 MHz */
+ /* channels: 1, 5, 9, 13... */
+ if ((idx & 0x3) == 0x1)
+ return 0; /* 20 MHz */
+ /* channels 3, 11, 19... */
+ if ((idx & 0x7) == 0x3)
+ return 1; /* 40 MHz */
+ /* channels 7, 23, 39.. */
+ if ((idx & 0xf) == 0x7)
+ return 2; /* 80 MHz */
+ /* channels 15, 47, 79...*/
+ if ((idx & 0x1f) == 0xf)
+ return 3; /* 160 MHz */
+
+ return -1;
+}
+
+
+bool is_6ghz_freq(int freq)
+{
+ if (freq < 5935 || freq > 7115)
+ return false;
+
+ if (freq == 5935)
+ return true;
+
+ if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
+ return false;
+
+ return true;
+}
+
+
+bool is_6ghz_op_class(u8 op_class)
+{
+ return op_class >= 131 && op_class <= 136;
+}
+
+
+bool is_6ghz_psc_frequency(int freq)
+{
+ int i;
+
+ if (!is_6ghz_freq(freq) || freq == 5935)
+ return false;
+ if ((((freq - 5950) / 5) & 0x3) != 0x1)
+ return false;
+
+ i = (freq - 5950 + 55) % 80;
+ if (i == 0)
+ i = (freq - 5950 + 55) / 80;
+
+ if (i >= 1 && i <= 15)
+ return true;
+
+ return false;
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -2012,3 +2401,301 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
return 0;
return !!(ie[2 + capab / 8] & BIT(capab % 8));
}
+
+
+bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
+ unsigned int capab)
+{
+ const u8 *end;
+ size_t flen, i;
+ u32 capabs = 0;
+
+ if (!rsnxe || rsnxe_len == 0)
+ return false;
+ end = rsnxe + rsnxe_len;
+ flen = (rsnxe[0] & 0x0f) + 1;
+ if (rsnxe + flen > end)
+ return false;
+ if (flen > 4)
+ flen = 4;
+ for (i = 0; i < flen; i++)
+ capabs |= rsnxe[i] << (8 * i);
+
+ return capabs & BIT(capab);
+}
+
+
+bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
+{
+ return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL,
+ rsnxe ? rsnxe[1] : 0, capab);
+}
+
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg)
+{
+ if (!edmg_enable) {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ return;
+ }
+
+ /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
+ switch (edmg_channel) {
+ case EDMG_CHANNEL_9:
+ edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_10:
+ edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_11:
+ edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_12:
+ edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_13:
+ edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ default:
+ if (primary_channel > 0 && primary_channel < 7) {
+ edmg->channels = BIT(primary_channel - 1);
+ edmg->bw_config = EDMG_BW_CONFIG_4;
+ } else {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ }
+ break;
+ }
+}
+
+
+/* Check if the requested EDMG configuration is a subset of the allowed
+ * EDMG configuration. */
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested)
+{
+ /*
+ * The validation check if the requested EDMG configuration
+ * is a subset of the allowed EDMG configuration:
+ * 1. Check that the requested channels are part (set) of the allowed
+ * channels.
+ * 2. P802.11ay defines the values of bw_config between 4 and 15.
+ * (bw config % 4) will give us 4 groups inside bw_config definition,
+ * inside each group we can check the subset just by comparing the
+ * bw_config value.
+ * Between this 4 groups, there is no subset relation - as a result of
+ * the P802.11ay definition.
+ * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
+ */
+ if (((requested.channels & allowed.channels) != requested.channels) ||
+ ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
+ requested.bw_config > allowed.bw_config)
+ return 0;
+
+ return 1;
+}
+
+
+int op_class_to_bandwidth(u8 op_class)
+{
+ switch (op_class) {
+ case 81:
+ case 82:
+ return 20;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ return 40;
+ case 115: /* channels 36,40,44,48; indoor only */
+ return 20;
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ return 40;
+ case 118: /* channels 52,56,60,64; dfs */
+ return 20;
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ return 40;
+ case 121: /* channels 100-140 */
+ return 20;
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ return 40;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
+ return 20;
+ case 126: /* channels 149,157,161,165,169,173; 40 MHz */
+ case 127: /* channels 153..177; 40 MHz */
+ return 40;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ return 80;
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
+ return 160;
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
+ return 80;
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ return 20;
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ return 40;
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ return 80;
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ return 160;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ return 20;
+ case 180: /* 60 GHz band, channels 1..8 */
+ return 2160;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ return 4320;
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ return 6480;
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ return 8640;
+ }
+
+ return 20;
+}
+
+
+int op_class_to_ch_width(u8 op_class)
+{
+ switch (op_class) {
+ case 81:
+ case 82:
+ return CHANWIDTH_USE_HT;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 115: /* channels 36,40,44,48; indoor only */
+ return CHANWIDTH_USE_HT;
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ return CHANWIDTH_USE_HT;
+ case 118: /* channels 52,56,60,64; dfs */
+ return CHANWIDTH_USE_HT;
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ return CHANWIDTH_USE_HT;
+ case 121: /* channels 100-140 */
+ return CHANWIDTH_USE_HT;
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169,171 */
+ return CHANWIDTH_USE_HT;
+ case 126: /* channels 149,157,165, 173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ return CHANWIDTH_80MHZ;
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
+ return CHANWIDTH_160MHZ;
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
+ return CHANWIDTH_80P80MHZ;
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ return CHANWIDTH_USE_HT;
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ return CHANWIDTH_USE_HT;
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ return CHANWIDTH_80MHZ;
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ return CHANWIDTH_160MHZ;
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ return CHANWIDTH_80P80MHZ;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ return CHANWIDTH_USE_HT;
+ case 180: /* 60 GHz band, channels 1..8 */
+ return CHANWIDTH_2160MHZ;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ return CHANWIDTH_4320MHZ;
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ return CHANWIDTH_6480MHZ;
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ return CHANWIDTH_8640MHZ;
+ }
+ return CHANWIDTH_USE_HT;
+}
+
+
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len)
+{
+ struct frag_ies_info *frag_ies = &elems->frag_ies;
+ struct wpabuf *buf;
+ unsigned int i;
+
+ if (!elems || !data || !len)
+ return NULL;
+
+ buf = wpabuf_alloc_copy(data, len);
+ if (!buf)
+ return NULL;
+
+ for (i = 0; i < frag_ies->n_frags; i++) {
+ int ret;
+
+ if (frag_ies->frags[i].eid != eid ||
+ frag_ies->frags[i].eid_ext != eid_ext)
+ continue;
+
+ ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
+ if (ret < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ /* Copy only the fragment data (without the EID and length) */
+ wpabuf_put_data(buf, frag_ies->frags[i].ie,
+ frag_ies->frags[i].ie_len);
+ }
+
+ return buf;
+}
+
+
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext)
+{
+ const u8 *data;
+ u8 len;
+
+ /*
+ * TODO: Defragmentation mechanism can be supported for all IEs. For now
+ * handle only those that are used (or use ieee802_11_defrag_data()).
+ */
+ switch (eid) {
+ case WLAN_EID_EXTENSION:
+ switch (eid_ext) {
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ data = elems->fils_hlp;
+ len = elems->fils_hlp_len;
+ break;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ data = elems->wrapped_data;
+ len = elems->wrapped_data_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid_ext=%u",
+ eid_ext);
+ return NULL;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid=%u", eid);
+ return NULL;
+ }
+
+ return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+}
diff --git a/contrib/wpa/src/common/ieee802_11_common.h b/contrib/wpa/src/common/ieee802_11_common.h
index 9b045b41a386..fe2b1bca601b 100644
--- a/contrib/wpa/src/common/ieee802_11_common.h
+++ b/contrib/wpa/src/common/ieee802_11_common.h
@@ -21,6 +21,7 @@ struct element {
struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
+#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info {
struct {
@@ -30,6 +31,21 @@ struct mb_ies_info {
u8 nof_ies;
};
+struct frag_ies_info {
+ struct {
+ u8 eid;
+ u8 eid_ext;
+ const u8 *ie;
+ u8 ie_len;
+ } frags[MAX_NUM_FRAG_IES_SUPPORTED];
+
+ u8 n_frags;
+
+ /* the last parsed element ID and element extension ID */
+ u8 last_eid;
+ u8 last_eid_ext;
+};
+
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@@ -40,6 +56,7 @@ struct ieee802_11_elems {
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
+ const u8 *rsnxe;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
@@ -84,7 +101,7 @@ struct ieee802_11_elems {
const u8 *fils_hlp;
const u8 *fils_ip_addr_assign;
const u8 *key_delivery;
- const u8 *fils_wrapped_data;
+ const u8 *wrapped_data;
const u8 *fils_pk;
const u8 *fils_nonce;
const u8 *owe_dh;
@@ -95,6 +112,11 @@ struct ieee802_11_elems {
const u8 *multi_ap;
const u8 *he_capabilities;
const u8 *he_operation;
+ const u8 *short_ssid_list;
+ const u8 *he_6ghz_band_cap;
+ const u8 *sae_pk;
+ const u8 *s1g_capab;
+ const u8 *pasn_params;
u8 ssid_len;
u8 supp_rates_len;
@@ -102,6 +124,7 @@ struct ieee802_11_elems {
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
+ u8 rsnxe_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
@@ -135,7 +158,7 @@ struct ieee802_11_elems {
u8 fils_hlp_len;
u8 fils_ip_addr_assign_len;
u8 key_delivery_len;
- u8 fils_wrapped_data_len;
+ u8 wrapped_data_len;
u8 fils_pk_len;
u8 owe_dh_len;
u8 power_capab_len;
@@ -145,8 +168,12 @@ struct ieee802_11_elems {
u8 multi_ap_len;
u8 he_capabilities_len;
u8 he_operation_len;
+ u8 short_ssid_list_len;
+ u8 sae_pk_len;
+ u8 pasn_params_len;
struct mb_ies_info mb_ies;
+ struct frag_ies_info frag_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -170,6 +197,18 @@ struct hostapd_wmm_ac_params {
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
+
+struct hostapd_tx_queue_params {
+ int aifs;
+ int cwmin;
+ int cwmax;
+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+#define NUM_TX_QUEUES 4
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
+ 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,
@@ -196,7 +235,8 @@ struct oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
+ BW4320, BW6480, BW8640} bw;
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
};
@@ -220,11 +260,20 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
+int center_idx_to_bw_6ghz(u8 idx);
+bool is_6ghz_freq(int freq);
+bool is_6ghz_op_class(u8 op_class);
+bool is_6ghz_psc_frequency(int freq);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
+bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
+ unsigned int capab);
+bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab);
+int op_class_to_bandwidth(u8 op_class);
+int op_class_to_ch_width(u8 op_class);
/* element iteration helpers */
#define for_each_element(_elem, _data, _datalen) \
@@ -273,4 +322,19 @@ static inline int for_each_element_completed(const struct element *element,
return (const u8 *) element == (const u8 *) data + datalen;
}
+struct ieee80211_edmg_config;
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg);
+
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested);
+
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len);
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/contrib/wpa/src/common/ieee802_11_defs.h b/contrib/wpa/src/common/ieee802_11_defs.h
index b0aa913bbc9a..519a13b1d064 100644
--- a/contrib/wpa/src/common/ieee802_11_defs.h
+++ b/contrib/wpa/src/common/ieee802_11_defs.h
@@ -22,7 +22,7 @@
#define WLAN_FC_PWRMGT 0x1000
#define WLAN_FC_MOREDATA 0x2000
#define WLAN_FC_ISWEP 0x4000
-#define WLAN_FC_ORDER 0x8000
+#define WLAN_FC_HTC 0x8000
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
@@ -50,6 +50,7 @@
#define WLAN_FC_STYPE_AUTH 11
#define WLAN_FC_STYPE_DEAUTH 12
#define WLAN_FC_STYPE_ACTION 13
+#define WLAN_FC_STYPE_ACTION_NO_ACK 14
/* control */
#define WLAN_FC_STYPE_PSPOLL 10
@@ -84,6 +85,7 @@
#define WLAN_AUTH_FILS_SK 4
#define WLAN_AUTH_FILS_SK_PFS 5
#define WLAN_AUTH_FILS_PK 6
+#define WLAN_AUTH_PASN 7
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -204,6 +206,9 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124
+#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
+#define WLAN_STATUS_SAE_PK 127
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -429,7 +434,7 @@
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194
-#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_TRANSMIT_POWER_ENVELOPE 195
#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
@@ -440,12 +445,17 @@
#define WLAN_EID_DEVICE_LOCATION 204
#define WLAN_EID_WHITE_SPACE_MAP 205
#define WLAN_EID_FTM_PARAMETERS 206
+#define WLAN_EID_S1G_BCN_COMPAT 213
+#define WLAN_EID_TWT 216
+#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_S1G_OPERATION 232
#define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240
#define WLAN_EID_DILS 241
#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_RSNX 244
#define WLAN_EID_EXTENSION 255
/* Element ID Extension (EID 255) values */
@@ -456,7 +466,7 @@
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7
-#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_WRAPPED_DATA 8
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@@ -470,6 +480,15 @@
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_SHORT_SSID_LIST 58
+#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
+#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88
+#define WLAN_EID_EXT_TCLAS_MASK 89
+#define WLAN_EID_EXT_REJECTED_GROUPS 92
+#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
+#define WLAN_EID_EXT_PASN_PARAMS 100
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -513,7 +532,6 @@
#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
-#define WLAN_EXT_CAPAB_
/* 41-43 - Service Interval Granularity */
#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
#define WLAN_EXT_CAPAB_U_APSD_COEX 45
@@ -534,7 +552,6 @@
#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
-#define WLAN_EXT_CAPAB_
/* 63-64 - Max Number of MSDUs In A-MSDU */
#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
@@ -551,6 +568,18 @@
#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
+#define WLAN_EXT_CAPAB_MSCS 85
+#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
+
+/* Extended RSN Capabilities */
+/* bits 0-3: Field length (n-1) */
+#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
+#define WLAN_RSNX_CAPAB_SAE_H2E 5
+#define WLAN_RSNX_CAPAB_SAE_PK 6
+#define WLAN_RSNX_CAPAB_SECURE_LTF 8
+#define WLAN_RSNX_CAPAB_SECURE_RTT 9
+#define WLAN_RSNX_CAPAB_PROT_RANGE_NEG 10
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -575,7 +604,12 @@
#define WLAN_ACTION_ROBUST_AV_STREAMING 19
#define WLAN_ACTION_UNPROTECTED_DMG 20
#define WLAN_ACTION_VHT 21
+#define WLAN_ACTION_S1G 22
+#define WLAN_ACTION_S1G_RELAY 23
+#define WLAN_ACTION_FLOW_CONTROL 24
+#define WLAN_ACTION_CTRL_RESP_MCS_NEG 25
#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_PROTECTED_FTM 34
#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Note: 128-255 used to report errors by setting category | 0x80 */
@@ -616,6 +650,7 @@
#define WLAN_PA_FTM_REQUEST 32
#define WLAN_PA_FTM 33
#define WLAN_PA_FILS_DISCOVERY 34
+#define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47
/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
* Table 9-332) */
@@ -673,6 +708,11 @@
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+/* Protected Fine Timing Frame Action Field value */
+#define WLAN_PROT_FTM_REQUEST 1
+#define WLAN_PROT_FTM 2
+#define WLAN_PROT_FTM_REPORT 3
+
/* Radio Measurement capabilities (from RM Enabled Capabilities element)
* IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
/* byte 1 (out of 5) */
@@ -785,6 +825,19 @@ enum nai_realm_eap_cred_type {
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
};
+/* Unprotected S1G Action field values for WLAN_ACTION_S1G */
+#define S1G_ACT_AID_SWITCH_REQUEST 0
+#define S1G_ACT_AID_SWITCH_RESPONSE 1
+#define S1G_ACT_SYNC_CONTROL 2
+#define S1G_ACT_STA_INFO_ANNOUNCE 3
+#define S1G_ACT_EDCA_PARAM_SET 4
+#define S1G_ACT_EL_OPERATION 5
+#define S1G_ACT_TWT_SETUP 6
+#define S1G_ACT_TWT_TEARDOWN 7
+#define S1G_ACT_SECT_GROUP_ID_LIST 8
+#define S1G_ACT_SECT_ID_FEEDBACK 9
+#define S1G_ACT_TWT_INFORMATION 11
+
/*
* IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
* measurement requests
@@ -1217,6 +1270,7 @@ struct ieee80211_ampe_ie {
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
@@ -1274,11 +1328,15 @@ struct ieee80211_ampe_ie {
#define VHT_RX_NSS_MAX_STREAMS 8
-/* VHT channel widths */
+/* VHT/EDMG channel widths */
#define CHANWIDTH_USE_HT 0
#define CHANWIDTH_80MHZ 1
#define CHANWIDTH_160MHZ 2
#define CHANWIDTH_80P80MHZ 3
+#define CHANWIDTH_2160MHZ 4
+#define CHANWIDTH_4320MHZ 5
+#define CHANWIDTH_6480MHZ 6
+#define CHANWIDTH_8640MHZ 7
#define HE_NSS_MAX_STREAMS 8
@@ -1298,6 +1356,10 @@ struct ieee80211_ampe_ie {
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
#define MULTI_AP_OUI_TYPE 0x1B
+#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
+#define DPP_CC_OUI_TYPE 0x1e
+#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
+#define SAE_PK_OUI_TYPE 0x1f
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -1595,6 +1657,7 @@ enum p2p_attr_id {
#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
+#define P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE BIT(6)
/* P2P Capability - Group Capability bitmap */
#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
@@ -1857,7 +1920,15 @@ enum wnm_sleep_mode_response_status {
/* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
- WNM_SLEEP_SUBELEM_IGTK = 1
+ WNM_SLEEP_SUBELEM_IGTK = 1,
+ WNM_SLEEP_SUBELEM_BIGTK = 2,
+};
+
+/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
+enum wnm_notification_Type {
+ WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
+ WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
+ WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
};
/* Channel Switch modes (802.11h) */
@@ -2073,7 +2144,7 @@ enum phy_type {
PHY_TYPE_VHT = 9,
};
-/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
/* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@@ -2090,6 +2161,7 @@ enum phy_type {
#define NEI_REP_BSSID_INFO_HT BIT(11)
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
+#define NEI_REP_BSSID_INFO_HE BIT(14)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@@ -2109,19 +2181,61 @@ struct ieee80211_he_capabilities {
u8 he_phy_capab_info[11];
/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
* and optional variable length PPE Thresholds field. */
- u8 optional[];
+ u8 optional[37];
} STRUCT_PACKED;
+#define IEEE80211_HE_CAPAB_MIN_LEN (6 + 11)
struct ieee80211_he_operation {
le32 he_oper_params; /* HE Operation Parameters[3] and
* BSS Color Information[1] */
le16 he_mcs_nss_set;
- u8 vht_op_info_chwidth;
- u8 vht_op_info_chan_center_freq_seg0_idx;
- u8 vht_op_info_chan_center_freq_seg1_idx;
- /* Followed by conditional MaxBSSID Indicator subfield (u8) */
+ /* Followed by conditional VHT Operation Information (3 octets),
+ * Max Co-Hosted BSSID Indicator subfield (1 octet), and/or 6 GHz
+ * Operation Information subfield (5 octets). */
+} STRUCT_PACKED;
+
+/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */
+struct ieee80211_he_6ghz_oper_info {
+ u8 primary_chan;
+ u8 control;
+ u8 chan_center_freq_seg0;
+ u8 chan_center_freq_seg1;
+ u8 min_rate;
} STRUCT_PACKED;
+#define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1))
+#define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2)
+
+/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */
+struct ieee80211_he_6ghz_band_cap {
+ /* Minimum MPDU Start Spacing B0..B2
+ * Maximum A-MPDU Length Exponent B3..B5
+ * Maximum MPDU Length B6..B7 */
+ le16 capab;
+} STRUCT_PACKED;
+
+#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_16K BIT(3)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_32K BIT(4)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_64K (BIT(3) | BIT(4))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_128K BIT(5)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_256K (BIT(3) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_512K (BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_1024K (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT 3
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_7991 BIT(6)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_11454 BIT(7)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT 6
+#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
+#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(9)
+#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(11)
+#define HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS BIT(12)
+#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
+
/*
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
*/
@@ -2139,6 +2253,8 @@ struct ieee80211_spatial_reuse {
/* HE Capabilities Information defines */
+#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2))
+
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
BIT(3) | BIT(4)))
@@ -2174,10 +2290,14 @@ struct ieee80211_spatial_reuse {
BIT(10) | BIT(11) | \
BIT(12) | BIT(13)))
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
+#define HE_OPERATION_VHT_OPER_INFO ((u32) BIT(14))
+#define HE_OPERATION_COHOSTED_BSS ((u32) BIT(15))
+#define HE_OPERATION_ER_SU_DISABLE ((u32) BIT(16))
+#define HE_OPERATION_6GHZ_OPER_INFO ((u32) BIT(17))
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
-#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
+#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
@@ -2221,7 +2341,108 @@ struct ieee80211_he_mu_edca_parameter_set {
/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
+/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
+#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
+
+/* IEEE P802.11ay/D4.0, 29.3.4 - Channelization */
+enum edmg_channel {
+ EDMG_CHANNEL_9 = 9,
+ EDMG_CHANNEL_10 = 10,
+ EDMG_CHANNEL_11 = 11,
+ EDMG_CHANNEL_12 = 12,
+ EDMG_CHANNEL_13 = 13,
+};
+
+/* Represent CB2 contiguous channels */
+#define EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) /* channels 1 and 2 */
+#define EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) /* channels 2 and 3 */
+#define EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3)) /* channels 3 and 4 */
+#define EDMG_CHANNEL_12_SUBCHANNELS (BIT(3) | BIT(4)) /* channels 4 and 5 */
+#define EDMG_CHANNEL_13_SUBCHANNELS (BIT(4) | BIT(5)) /* channels 5 and 6 */
+
+/**
+ * enum edmg_bw_config - Allowed channel bandwidth configurations
+ * @EDMG_BW_CONFIG_4: 2.16 GHz
+ * @EDMG_BW_CONFIG_5: 2.16 GHz and 4.32 GHz
+ *
+ * IEEE P802.11ay/D4.0, 9.4.2.251 (EDMG Operation element),
+ * Table 13 (Channel BW Configuration subfield definition)
+ */
+enum edmg_bw_config {
+ EDMG_BW_CONFIG_4 = 4,
+ EDMG_BW_CONFIG_5 = 5,
+};
+
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
+/* Robust AV streaming Action field values */
+enum robust_av_streaming_action {
+ ROBUST_AV_SCS_REQ = 0,
+ ROBUST_AV_SCS_RESP = 1,
+ ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2,
+ ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3,
+ ROBUST_AV_MSCS_REQ = 4,
+ ROBUST_AV_MSCS_RESP = 5,
+};
+
+enum scs_request_type {
+ SCS_REQ_ADD = 0,
+ SCS_REQ_REMOVE = 1,
+ SCS_REQ_CHANGE = 2,
+};
+
+/* Optional subelement IDs for MSCS Descriptor element */
+enum mscs_description_subelem {
+ MCSC_SUBELEM_STATUS = 1,
+};
+
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687b - FILS Discovery Frame Control subfield format
+ */
+#define FD_FRAME_CTL_CAP_PRESENT ((u16) BIT(5))
+#define FD_FRAME_CTL_SHORT_SSID_PRESENT ((u16) BIT(6))
+#define FD_FRAME_CTL_AP_CSN_PRESENT ((u16) BIT(7))
+#define FD_FRAME_CTL_ANO_PRESENT ((u16) BIT(8))
+#define FD_FRAME_CTL_FREQ_SEG1_PRESENT ((u16) BIT(9))
+#define FD_FRAME_CTL_PRI_CHAN_PRESENT ((u16) BIT(10))
+#define FD_FRAME_CTL_RSN_INFO_PRESENT ((u16) BIT(11))
+#define FD_FRAME_CTL_LENGTH_PRESENT ((u16) BIT(12))
+#define FD_FRAME_CTL_MD_PRESENT ((u16) BIT(13))
+
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687c - FD Capability subfield format
+ */
+#define FD_CAP_ESS BIT(0)
+#define FD_CAP_PRIVACY BIT(1)
+#define FD_CAP_MULTI_BSSID_PRESENT BIT(9)
+
+#define FD_CAP_BSS_CHWIDTH_20 0
+#define FD_CAP_BSS_CHWIDTH_40 1
+#define FD_CAP_BSS_CHWIDTH_80 2
+#define FD_CAP_BSS_CHWIDTH_160_80_80 3
+#define FD_CAP_BSS_CHWIDTH_SHIFT 2
+
+#define FD_CAP_NSS_1 0
+#define FD_CAP_NSS_2 1
+#define FD_CAP_NSS_3 2
+#define FD_CAP_NSS_4 3
+#define FD_CAP_NSS_5_8 4
+#define FD_CAP_NSS_SHIFT 5
+
+#define FD_CAP_PHY_INDEX_HR_DSSS 0
+#define FD_CAP_PHY_INDEX_ERP_OFDM 1
+#define FD_CAP_PHY_INDEX_HT 2
+#define FD_CAP_PHY_INDEX_VHT 3
+#define FD_CAP_PHY_INDEX_HE 4 /* P802.11ax */
+#define FD_CAP_PHY_INDEX_SHIFT 10
+
+/*
+ * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning
+ */
+#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/contrib/wpa/src/common/linux_bridge.h b/contrib/wpa/src/common/linux_bridge.h
new file mode 100644
index 000000000000..84386e60f750
--- /dev/null
+++ b/contrib/wpa/src/common/linux_bridge.h
@@ -0,0 +1,39 @@
+/*
+ * Linux bridge configuration kernel interface
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_BRIDGE_H
+#define LINUX_BRIDGE_H
+
+/* This ioctl is defined in linux/sockios.h */
+
+#ifndef SIOCBRADDBR
+#define SIOCBRADDBR 0x89a0
+#endif
+#ifndef SIOCBRDELBR
+#define SIOCBRDELBR 0x89a1
+#endif
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2
+#endif
+#ifndef SIOCBRDELIF
+#define SIOCBRDELIF 0x89a3
+#endif
+
+/* This interface is defined in linux/if_bridge.h */
+
+#define BRCTL_GET_VERSION 0
+#define BRCTL_GET_BRIDGES 1
+#define BRCTL_ADD_BRIDGE 2
+#define BRCTL_DEL_BRIDGE 3
+#define BRCTL_ADD_IF 4
+#define BRCTL_DEL_IF 5
+#define BRCTL_GET_BRIDGE_INFO 6
+#define BRCTL_GET_PORT_LIST 7
+#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
+
+#endif /* LINUX_BRIDGE_H */
diff --git a/contrib/wpa/src/common/linux_vlan.h b/contrib/wpa/src/common/linux_vlan.h
new file mode 100644
index 000000000000..8a1dd6e46640
--- /dev/null
+++ b/contrib/wpa/src/common/linux_vlan.h
@@ -0,0 +1,52 @@
+/*
+ * Linux VLAN configuration kernel interface
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_VLAN_H
+#define LINUX_VLAN_H
+
+/* This ioctl is defined in linux/sockios.h */
+
+#ifndef SIOCSIFVLAN
+#define SIOCSIFVLAN 0x8983
+#endif /* SIOCSIFVLAN */
+
+/* This interface is defined in linux/if_vlan.h */
+
+#define ADD_VLAN_CMD 0
+#define DEL_VLAN_CMD 1
+#define SET_VLAN_INGRESS_PRIORITY_CMD 2
+#define SET_VLAN_EGRESS_PRIORITY_CMD 3
+#define GET_VLAN_INGRESS_PRIORITY_CMD 4
+#define GET_VLAN_EGRESS_PRIORITY_CMD 5
+#define SET_VLAN_NAME_TYPE_CMD 6
+#define SET_VLAN_FLAG_CMD 7
+#define GET_VLAN_REALDEV_NAME_CMD 8
+#define GET_VLAN_VID_CMD 9
+
+#define VLAN_NAME_TYPE_PLUS_VID 0
+#define VLAN_NAME_TYPE_RAW_PLUS_VID 1
+#define VLAN_NAME_TYPE_PLUS_VID_NO_PAD 2
+#define VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD 3
+
+struct vlan_ioctl_args {
+ int cmd;
+ char device1[24];
+
+ union {
+ char device2[24];
+ int VID;
+ unsigned int skb_priority;
+ unsigned int name_type;
+ unsigned int bind_type;
+ unsigned int flag;
+ } u;
+
+ short vlan_qos;
+};
+
+#endif /* LINUX_VLAN_H */
diff --git a/contrib/wpa/src/common/ocv.c b/contrib/wpa/src/common/ocv.c
index 06badfbfb454..c9dc14fa6c09 100644
--- a/contrib/wpa/src/common/ocv.c
+++ b/contrib/wpa/src/common/ocv.c
@@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
oci->sec_channel = 1;
else if (op_class_map->bw == BW40MINUS)
oci->sec_channel = -1;
+ else if (op_class_map->bw == BW40)
+ oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
return 0;
}
@@ -95,23 +97,24 @@ int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
}
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx)
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx)
{
struct oci_info oci;
if (!oci_ie) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: did not receive mandatory OCI");
- return -1;
+ "did not receive mandatory OCI");
+ return OCI_NOT_FOUND;
}
if (oci_ie_len != 3) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: received OCI of unexpected length (%d)",
+ "received OCI of unexpected length (%d)",
(int) oci_ie_len);
- return -1;
+ return OCI_INVALID_LENGTH;
}
os_memset(&oci, 0, sizeof(oci));
@@ -120,25 +123,25 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
oci.seg1_idx = oci_ie[2];
if (ocv_derive_all_parameters(&oci) != 0) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: unable to interpret received OCI");
- return -1;
+ "unable to interpret received OCI");
+ return OCI_PARSE_ERROR;
}
/* Primary frequency used to send frames to STA must match the STA's */
if ((int) ci->frequency != oci.freq) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "primary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->frequency, oci.freq);
- return -1;
+ return OCI_PRIMARY_FREQ_MISMATCH;
}
/* We shouldn't transmit with a higher bandwidth than the STA supports
*/
if (tx_chanwidth > oci.chanwidth) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+ "channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
tx_chanwidth, oci.chanwidth);
- return -1;
+ return OCI_CHANNEL_WIDTH_MISMATCH;
}
/*
@@ -150,9 +153,9 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
ci->sec_channel != oci.sec_channel) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->sec_channel, oci.sec_channel);
- return -1;
+ return OCI_SECONDARY_FREQ_MISMATCH;
}
/*
@@ -163,10 +166,10 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
ci->chanwidth == CHAN_WIDTH_80P80) &&
tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+ "frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
tx_seg1_idx, oci.seg1_idx);
- return -1;
+ return OCI_SEG_1_INDEX_MISMATCH;
}
- return 0;
+ return OCI_SUCCESS;
}
diff --git a/contrib/wpa/src/common/ocv.h b/contrib/wpa/src/common/ocv.h
index 6379d9d06c9a..7fa4522c12c2 100644
--- a/contrib/wpa/src/common/ocv.h
+++ b/contrib/wpa/src/common/ocv.h
@@ -27,14 +27,21 @@ struct oci_info {
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+enum oci_verify_result {
+ OCI_SUCCESS, OCI_NOT_FOUND, OCI_INVALID_LENGTH, OCI_PARSE_ERROR,
+ OCI_PRIMARY_FREQ_MISMATCH, OCI_CHANNEL_WIDTH_MISMATCH,
+ OCI_SECONDARY_FREQ_MISMATCH, OCI_SEG_1_INDEX_MISMATCH
+};
+
extern char ocv_errorstr[256];
int ocv_derive_all_parameters(struct oci_info *oci);
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx);
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx);
#endif /* OCV_H */
diff --git a/contrib/wpa/src/common/privsep_commands.h b/contrib/wpa/src/common/privsep_commands.h
index b85c6c347a79..d2c4bbd5e8b6 100644
--- a/contrib/wpa/src/common/privsep_commands.h
+++ b/contrib/wpa/src/common/privsep_commands.h
@@ -82,6 +82,7 @@ struct privsep_cmd_set_key {
size_t seq_len;
u8 key[32];
size_t key_len;
+ enum key_flag key_flag;
};
enum privsep_event {
diff --git a/contrib/wpa/src/common/ptksa_cache.c b/contrib/wpa/src/common/ptksa_cache.c
new file mode 100644
index 000000000000..6a053d65019d
--- /dev/null
+++ b/contrib/wpa/src/common/ptksa_cache.c
@@ -0,0 +1,321 @@
+/*
+ * RSN PTKSA cache implementation
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "eloop.h"
+#include "common/ptksa_cache.h"
+
+#define PTKSA_CACHE_MAX_ENTRIES 16
+
+struct ptksa_cache {
+ struct dl_list ptksa;
+ unsigned int n_ptksa;
+};
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa);
+
+
+static void ptksa_cache_free_entry(struct ptksa_cache *ptksa,
+ struct ptksa_cache_entry *entry)
+{
+ ptksa->n_ptksa--;
+
+ dl_list_del(&entry->list);
+ bin_clear_free(entry, sizeof(*entry));
+}
+
+
+static void ptksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ptksa_cache *ptksa = eloop_ctx;
+ struct ptksa_cache_entry *e, *next;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list) {
+ if (e->expiration > now.sec)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ }
+
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e;
+ int sec;
+ struct os_reltime now;
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+
+ if (!ptksa || !ptksa->n_ptksa)
+ return;
+
+ e = dl_list_first(&ptksa->ptksa, struct ptksa_cache_entry, list);
+ if (!e)
+ return;
+
+ os_get_reltime(&now);
+ sec = e->expiration - now.sec;
+ if (sec < 0)
+ sec = 0;
+
+ eloop_register_timeout(sec + 1, 0, ptksa_cache_expire, ptksa, NULL);
+}
+
+
+/*
+ * ptksa_cache_init - Initialize PTKSA cache
+ *
+ * Returns: Pointer to PTKSA cache data or %NULL on failure
+ */
+struct ptksa_cache * ptksa_cache_init(void)
+{
+ struct ptksa_cache *ptksa = os_zalloc(sizeof(struct ptksa_cache));
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Initializing");
+
+ if (ptksa)
+ dl_list_init(&ptksa->ptksa);
+
+ return ptksa;
+}
+
+
+/*
+ * ptksa_cache_deinit - Free all entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ */
+void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e, *next;
+
+ if (!ptksa)
+ return;
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Deinit. n_ptksa=%u", ptksa->n_ptksa);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list)
+ ptksa_cache_free_entry(ptksa, e);
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+ os_free(ptksa);
+}
+
+
+/*
+ * ptksa_cache_get - Fetch a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ * Returns: Pointer to PTKSA cache entry or %NULL if no match was found
+ */
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e;
+
+ if (!ptksa)
+ return NULL;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher))
+ return e;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * ptksa_cache_list - Dump text list of entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PTKSA cache contents for the ctrl_iface PTKSA command.
+ */
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len)
+{
+ struct ptksa_cache_entry *e;
+ int i = 0, ret;
+ char *pos = buf;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return 0;
+
+ os_get_reltime(&now);
+
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / ADDR / Cipher / expiration (secs) / TK / KDK\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ ret = os_snprintf(pos, buf + len - pos, "%u " MACSTR,
+ i, MAC2STR(e->addr));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " %s %lu ",
+ wpa_cipher_txt(e->cipher),
+ e->expiration - now.sec);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.tk,
+ e->ptk.tk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " ");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.kdk,
+ e->ptk.kdk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, "\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ i++;
+ }
+
+ return pos - buf;
+}
+
+
+/*
+ * ptksa_cache_flush - Flush PTKSA cache entries
+ *
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ */
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e, *next;
+ bool removed = false;
+
+ if (!ptksa)
+ return;
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa, struct ptksa_cache_entry,
+ list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "Flush PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ removed = true;
+ }
+ }
+
+ if (removed)
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+/*
+ * ptksa_cache_add - Add a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address
+ * @cipher: The cipher used
+ * @life_time: The PTK life time in seconds
+ * @ptk: The PTK
+ * Returns: Pointer to the added PTKSA cache entry or %NULL on error
+ *
+ * This function creates a PTKSA entry and adds it to the PTKSA cache.
+ * If an old entry is already in the cache for the same peer and cipher
+ * this entry will be replaced with the new entry.
+ */
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk)
+{
+ struct ptksa_cache_entry *entry, *tmp;
+ struct os_reltime now;
+
+ if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
+ return NULL;
+
+ /* remove a previous entry if present */
+ ptksa_cache_flush(ptksa, addr, cipher);
+
+ /* no place to add another entry */
+ if (ptksa->n_ptksa >= PTKSA_CACHE_MAX_ENTRIES)
+ return NULL;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return NULL;
+
+ dl_list_init(&entry->list);
+ os_memcpy(entry->addr, addr, ETH_ALEN);
+ entry->cipher = cipher;
+
+ os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk));
+
+ os_get_reltime(&now);
+ entry->expiration = now.sec + life_time;
+
+ dl_list_for_each(tmp, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if (tmp->expiration > entry->expiration)
+ break;
+ }
+
+ /*
+ * If the list was empty add to the head; otherwise if the expiration is
+ * later then all other entries, add it to the end of the list;
+ * otherwise add it before the relevant entry.
+ */
+ if (!tmp)
+ dl_list_add(&ptksa->ptksa, &entry->list);
+ else if (tmp->expiration < entry->expiration)
+ dl_list_add(&tmp->list, &entry->list);
+ else
+ dl_list_add_tail(&tmp->list, &entry->list);
+
+ ptksa->n_ptksa++;
+ wpa_printf(MSG_DEBUG,
+ "Added PTKSA cache entry addr=" MACSTR " cipher=%u",
+ MAC2STR(addr), cipher);
+
+ return entry;
+}
diff --git a/contrib/wpa/src/common/ptksa_cache.h b/contrib/wpa/src/common/ptksa_cache.h
new file mode 100644
index 000000000000..28ef29144647
--- /dev/null
+++ b/contrib/wpa/src/common/ptksa_cache.h
@@ -0,0 +1,79 @@
+/*
+ * RSN PTKSA cache interface
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PTKSA_CACHE_H
+#define PTKSA_CACHE_H
+
+#include "wpa_common.h"
+#include "defs.h"
+#include "list.h"
+
+/**
+ * struct ptksa_cache_entry - PTKSA cache entry
+ */
+struct ptksa_cache_entry {
+ struct dl_list list;
+ struct wpa_ptk ptk;
+ os_time_t expiration;
+ u32 cipher;
+ u8 addr[ETH_ALEN];
+};
+
+#ifdef CONFIG_PTKSA_CACHE
+
+struct ptksa_cache;
+
+struct ptksa_cache * ptksa_cache_init(void);
+void ptksa_cache_deinit(struct ptksa_cache *ptksa);
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher);
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len);
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk);
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher);
+
+#else /* CONFIG_PTKSA_CACHE */
+
+static inline struct ptksa_cache * ptksa_cache_init(void)
+{
+ return (struct ptksa_cache *) 1;
+}
+
+static inline void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_get(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ return NULL;
+}
+
+static inline int ptksa_cache_list(struct ptksa_cache *ptksa,
+ char *buf, size_t len)
+{
+ return -1;
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ return NULL;
+}
+
+static inline void ptksa_cache_flush(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+}
+
+#endif /* CONFIG_PTKSA_CACHE */
+#endif /* PTKSA_CACHE_H */
diff --git a/contrib/wpa/src/common/qca-vendor.h b/contrib/wpa/src/common/qca-vendor.h
index ff8c22a7546c..47666f04ae7c 100644
--- a/contrib/wpa/src/common/qca-vendor.h
+++ b/contrib/wpa/src/common/qca-vendor.h
@@ -1,7 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,10 @@
#define OUI_QCA 0x001374
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
/**
* enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
*/
@@ -72,7 +76,7 @@ enum qca_radiotap_vendor_ids {
*
* @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
- * hostapd.
+ * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
@@ -170,6 +174,27 @@ enum qca_radiotap_vendor_ids {
* to notify the connected station's status. The attributes for this
* command are defined in enum qca_wlan_vendor_attr_link_properties.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: Command to configure the enabled band(s)
+ * to the driver. This command sets the band(s) through either the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE or
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK (or both).
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE refers enum qca_set_band as unsigned
+ * integer values and QCA_WLAN_VENDOR_ATTR_SETBAND_MASK refers it as 32
+ * bit unsigned bitmask values. The allowed values for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE are limited to QCA_SETBAND_AUTO,
+ * QCA_SETBAND_5G, and QCA_SETBAND_2G. Other values/bitmasks are valid for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. The attribute
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is deprecated and the recommendation
+ * is to use the QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. If the both attributes
+ * are included for backwards compatibility, the configurations through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK will take the precedence with drivers
+ * that support both attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
+ * DFS policy and channel hint for ACS operation. This command uses the
+ * attributes defined in enum qca_wlan_vendor_attr_acs_config and
+ * enum qca_acs_dfs_mode.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
* start the P2P Listen offload function in device and pass the listen
* channel, period, interval, count, device types, and vendor specific
@@ -487,7 +512,9 @@ enum qca_radiotap_vendor_ids {
* @QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG: This command is used to
* configure parameters per peer to capture Channel Frequency Response
* (CFR) and enable Periodic CFR capture. The attributes for this command
- * are defined in enum qca_wlan_vendor_peer_cfr_capture_attr.
+ * are defined in enum qca_wlan_vendor_peer_cfr_capture_attr. This command
+ * can also be used to send CFR data from the driver to userspace when
+ * netlink events are used to send CFR data.
*
* @QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT: Event to indicate changes
* in throughput dynamically. The driver estimates the throughput based on
@@ -584,10 +611,114 @@ enum qca_radiotap_vendor_ids {
* by the firmware to user space for persistent storage. The attributes
* defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
* the parameters.
- * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command is used to send OEM data
- * binary blobs from application/service to firmware. The attributes
- * defined in enum qca_wlan_vendor_attr_oem_data_params are used to deliver
- * the parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command/event is used to
+ * send/receive OEM data binary blobs to/from application/service to/from
+ * firmware. The attributes defined in enum
+ * qca_wlan_vendor_attr_oem_data_params are used to deliver the
+ * parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT: This command/event is used
+ * to send/receive avoid frequency data using
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext.
+ * This new command is alternative to existing command
+ * QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event
+ * is using stream of bytes instead of structured data using vendor
+ * attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to
+ * add the STA node details in driver/firmware. Attributes for this event
+ * are specified in enum qca_wlan_vendor_attr_add_sta_node_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE: This command is used to set BT
+ * coex chain mode from application/service.
+ * The attributes defined in enum qca_vendor_attr_btc_chain_mode are used
+ * to deliver the parameters.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO: This vendor subcommand is used to
+ * get information of a station from driver to userspace. This command can
+ * be used in both STA and AP modes. For STA mode, it provides information
+ * of the current association when in connected state or the last
+ * association when in disconnected state. For AP mode, only information
+ * of the currently connected stations is available. This command uses
+ * attributes defined in enum qca_wlan_vendor_attr_get_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT: This acts as an event.
+ * Host drivers can request the user space entity to set the SAR power
+ * limits with this event. Accordingly, the user space entity is expected
+ * to set the SAR power limits. Host drivers can retry this event to the
+ * user space for the SAR power limits configuration from user space. If
+ * the driver does not get the SAR power limits from user space for all
+ * the retried attempts, it can configure a default SAR power limit.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO: This acts as a vendor event and
+ * is used to update the information about the station from the driver to
+ * userspace. Uses attributes from enum
+ * qca_wlan_vendor_attr_update_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON: This acts as an event.
+ * The host driver initiates the disconnection for scenarios such as beacon
+ * miss, NUD failure, peer kick out, etc. The disconnection indication
+ * through cfg80211_disconnected() expects the reason codes from enum
+ * ieee80211_reasoncode which does not signify these various reasons why
+ * the driver has triggered the disconnection. This event will be used to
+ * send the driver specific reason codes by the host driver to userspace.
+ * Host drivers should trigger this event and pass the respective reason
+ * code immediately prior to triggering cfg80211_disconnected(). The
+ * attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_driver_disconnect_reason.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC: This vendor subcommand is used to
+ * add/delete TSPEC for each AC. One command is for one specific AC only.
+ * This command can only be used in STA mode and the STA must be
+ * associated with an AP when the command is issued. Uses attributes
+ * defined in enum qca_wlan_vendor_attr_config_tspec.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT: Vendor subcommand to configure TWT.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_config_twt.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GETBAND: Command to get the enabled band(s) from
+ * the driver. The band configurations obtained are referred through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS: Vendor subcommand/event for medium
+ * assessment.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_medium_assess.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID: This acts as a vendor event and is
+ * used to update SSID information in hostapd when it is updated in the
+ * driver. Uses the attribute NL80211_ATTR_SSID.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS: This vendor subcommand is used by
+ * the driver to send opaque data from the firmware to userspace. The
+ * driver sends an event to userspace whenever such data is received from
+ * the firmware.
+ *
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA is used as the attribute to
+ * send this opaque data for this event.
+ *
+ * The format of the opaque data is specific to the particular firmware
+ * version and there is no guarantee of the format remaining same.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS: This acts as an event.
+ * The host driver selects Tx VDEV, and notifies user. The attributes
+ * used with this event are defined in enum
+ * qca_wlan_vendor_attr_mbssid_tx_vdev_status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY: Vendor command to
+ * configure the concurrent session policies when multiple STA interfaces
+ * are (getting) active. The attributes used by this command are defined
+ * in enum qca_wlan_vendor_attr_concurrent_sta_policy.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS: Userspace can use this command
+ * to query usable channels for different interface types such as STA,
+ * AP, P2P GO, P2P Client, NAN, etc. The driver shall report all usable
+ * channels in the response based on country code, different static
+ * configurations, concurrency combinations, etc. The attributes used
+ * with this command are defined in
+ * enum qca_wlan_vendor_attr_usable_channels.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY: This vendor subcommand is used
+ * to get DFS radar history from the driver to userspace. The driver
+ * returns QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES attribute with an
+ * array of nested entries.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -687,7 +818,8 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
- /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116,
+ /* 117 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
@@ -759,6 +891,23 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
+ QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT = 183,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
+ QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
+ QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO = 186,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
+ QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC = 190,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT = 191,
+ QCA_NL80211_VENDOR_SUBCMD_GETBAND = 192,
+ QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS = 193,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195,
+ QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196,
+ QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY = 197,
+ QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS = 198,
+ QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY = 199,
};
enum qca_wlan_vendor_attr {
@@ -789,7 +938,11 @@ enum qca_wlan_vendor_attr {
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. */
+ /* Unsigned 32-bit value from enum qca_set_band. The allowed values for
+ * this attribute are limited to QCA_SETBAND_AUTO, QCA_SETBAND_5G, and
+ * QCA_SETBAND_2G. This attribute is deprecated. Recommendation is to
+ * use QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead.
+ */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
/* Dummy (NOP) attribute for 64 bit padding */
QCA_WLAN_VENDOR_ATTR_PAD = 13,
@@ -952,6 +1105,15 @@ enum qca_wlan_vendor_attr {
*/
QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
+ /* Unsigned 32-bitmask value from enum qca_set_band. Substitutes the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE for which only a subset
+ * of single values from enum qca_set_band are valid. This attribute
+ * uses bitmask combinations to define the respective allowed band
+ * combinations and this attributes takes precedence over
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE if both attributes are included.
+ */
+ QCA_WLAN_VENDOR_ATTR_SETBAND_MASK = 43,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -1095,31 +1257,178 @@ enum qca_wlan_vendor_attr_p2p_listen_offload {
QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_attr_acs_offload - Defines attributes to be used with
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: Required (u8).
+ * Used with event to notify the primary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY instead.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: Required (u8).
+ * Used with event to notify the secondary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is still used if either of
+ * the driver or user space application doesn't support 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: Required (u8).
+ * (a) Used with command to configure hw_mode from
+ * enum qca_wlan_vendor_acs_hw_mode for ACS operation.
+ * (b) Also used with event to notify the hw_mode of selected primary channel
+ * in ACS operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT mode.
+ * Disable (flag attribute not present) - HT disabled and
+ * Enable (flag attribute present) - HT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT40 mode.
+ * Disable (flag attribute not present) - HT40 disabled and
+ * Enable (flag attribute present) - HT40 enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for VHT mode.
+ * Disable (flag attribute not present) - VHT disabled and
+ * Enable (flag attribute present) - VHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH: Optional (u16) with command and
+ * mandatory with event.
+ * If specified in command path, ACS operation is configured with the given
+ * channel width (in MHz).
+ * In event path, specifies the channel width of the primary channel selected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure channel list using an array of
+ * channel numbers (u8).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 0 center channel number selected in
+ * ACS operation. The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center frequency index
+ * of the primary 80 MHz segment for 160 MHz and 80+80 MHz channels.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 1 center channel number selected in
+ * ACS operation. The value is zero for 20 MHz, 40 MHz, and 80 MHz channels.
+ * The value is the index of the channel center frequency for 160 MHz channels
+ * and the center frequency index of the secondary 80 MHz segment for 80+80 MHz
+ * channels.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure the channel list using an array of channel
+ * center frequencies in MHz (u32).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver first parses the frequency list and if it fails to get a frequency
+ * list, parses the channel list specified using
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST (considers only 2 GHz and 5 GHz channels in
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY: Required (u32).
+ * Used with event to notify the primary channel center frequency (MHz) selected
+ * in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY: Required (u32).
+ * Used with event to notify the secondary channel center frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 0 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 1 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED: Flag attribute.
+ * Used with command to notify the driver of EDMG request for ACS
+ * operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL: Optional (u8).
+ * Used with event to notify the EDMG channel number selected in ACS
+ * operation.
+ * EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ */
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
- 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,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE = 3,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED = 4,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED = 5,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED = 6,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH = 7,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST = 8,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL = 9,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL = 10,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST = 11,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY = 12,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_acs_hw_mode - Defines HW mode to be used with the
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_ACS_MODE_IEEE80211B: 802.11b mode
+ * @QCA_ACS_MODE_IEEE80211G: 802.11g mode
+ * @QCA_ACS_MODE_IEEE80211A: 802.11a mode
+ * @QCA_ACS_MODE_IEEE80211AD: 802.11ad mode
+ * @QCA_ACS_MODE_IEEE80211ANY: all modes
+ * @QCA_ACS_MODE_IEEE80211AX: 802.11ax mode
+ */
enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211B,
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
QCA_ACS_MODE_IEEE80211ANY,
+ QCA_ACS_MODE_IEEE80211AX,
};
/**
@@ -1151,6 +1460,32 @@ enum qca_wlan_vendor_acs_hw_mode {
* @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
* managed regulatory.
* @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
+ * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
+ * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
+ * @QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG: Device is capable of receiving
+ * and applying thermal configuration through
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from
+ * userspace.
+ * @QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R: Device supports Adaptive 11r.
+ * With Adaptive 11r feature, access points advertise the vendor
+ * specific IEs and MDE but do not include FT AKM in the RSNE.
+ * The Adaptive 11r supported stations are expected to identify
+ * such vendor specific IEs and connect to the AP in FT mode though
+ * the profile is configured in non-FT mode.
+ * The driver-based SME cases also need to have this support for
+ * Adaptive 11r to handle the connection and roaming scenarios.
+ * This flag indicates the support for the same to the user space.
+ * @QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS: Device supports
+ * concurrent network sessions on different Wi-Fi bands. This feature
+ * capability is attributed to the hardware's capability to support
+ * the same (e.g., DBS).
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT: Flag indicating whether the
+ * responses for the respective TWT operations are asynchronous (separate
+ * event message) from the driver. If not specified, the responses are
+ * synchronous (in vendor command reply) to the request. Each TWT
+ * operation is specifically mentioned (against its respective
+ * documentation) to support either of these or both modes.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1163,6 +1498,12 @@ enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
+ QCA_WLAN_VENDOR_FEATURE_11AX = 9,
+ QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
+ QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
+ QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12,
+ QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
+ QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1342,9 +1683,10 @@ enum qca_iface_type {
};
enum qca_set_band {
- QCA_SETBAND_AUTO,
- QCA_SETBAND_5G,
- QCA_SETBAND_2G,
+ QCA_SETBAND_AUTO = 0,
+ QCA_SETBAND_5G = BIT(0),
+ QCA_SETBAND_2G = BIT(1),
+ QCA_SETBAND_6G = BIT(2),
};
/**
@@ -1388,11 +1730,22 @@ enum qca_vendor_attr_tsf_cmd {
* @QCA_TSF_CAPTURE: Initiate TSF Capture
* @QCA_TSF_GET: Get TSF capture value
* @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value
+ * @QCA_TSF_AUTO_REPORT_ENABLE: Used in STA mode only. Once set, the target
+ * will automatically send TSF report to the host. To query
+ * QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY, this operation needs to be
+ * initiated first.
+ * @QCA_TSF_AUTO_REPORT_DISABLE: Used in STA mode only. Once set, the target
+ * will not automatically send TSF report to the host. If
+ * QCA_TSF_AUTO_REPORT_ENABLE is initiated and
+ * QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY is not queried anymore, this
+ * operation needs to be initiated.
*/
enum qca_tsf_cmd {
QCA_TSF_CAPTURE,
QCA_TSF_GET,
QCA_TSF_SYNC_GET,
+ QCA_TSF_AUTO_REPORT_ENABLE,
+ QCA_TSF_AUTO_REPORT_DISABLE,
};
/**
@@ -1472,6 +1825,8 @@ enum qca_vendor_attr_wisa_cmd {
* (not including the Element ID Extension field). Please note that the
* draft is still work in progress and this element payload is subject to
* change.
+ *
+ * @QCA_VENDOR_ELEM_ALLPLAY: Allplay element
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
@@ -1480,6 +1835,7 @@ enum qca_vendor_element_id {
QCA_VENDOR_ELEM_RAPS = 3,
QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
+ QCA_VENDOR_ELEM_ALLPLAY = 6,
};
/**
@@ -1504,6 +1860,9 @@ enum qca_vendor_element_id {
* randomisation
* @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
* specific BSSID to scan for.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in
+ * microseconds. This is a common value which applies across all
+ * frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -1518,6 +1877,7 @@ enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
+ QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -1872,25 +2232,276 @@ enum qca_wlan_vendor_attr_config {
* take the union of IEs from both of these interfaces and send in
* further disassoc/deauth frames.
*/
- QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
/* 8-bit unsigned value for ELNA bypass.
* 1-Enable, 0-Disable
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send the Beacon Report Response with failure reason for the
+ * scenarios where STA cannot honor the Beacon Report Request from AP.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL = 60,
+
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send roam reason information in the Reassociation Request frame to
+ * the target AP when roaming within the same ESS.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+
+ /* 32-bit unsigned value to configure different PHY modes to the
+ * driver/firmware. The possible values are defined in
+ * enum qca_wlan_vendor_phy_mode. The configuration will be reset to
+ * default value, i.e., QCA_WLAN_VENDOR_PHY_MODE_AUTO upon restarting
+ * the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE = 62,
+
+ /* 8-bit unsigned value to configure the maximum supported channel width
+ * for STA mode. If this value is configured when STA is in connected
+ * state, it should not exceed the negotiated channel width. If it is
+ * configured when STA is in disconnected state, the configured value
+ * will take effect for the next immediate connection.
+ * Possible values are:
+ * NL80211_CHAN_WIDTH_20
+ * NL80211_CHAN_WIDTH_40
+ * NL80211_CHAN_WIDTH_80
+ * NL80211_CHAN_WIDTH_80P80
+ * NL80211_CHAN_WIDTH_160
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH = 63,
+
+ /* 8-bit unsigned value to enable/disable dynamic bandwidth adjustment.
+ * This attribute is only applicable for STA mode. When dynamic
+ * bandwidth adjustment is disabled, STA will use static channel width
+ * the value of which is negotiated during connection.
+ * 1-enable (default), 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW = 64,
+
+ /* 8-bit unsigned value to configure the maximum number of subframes of
+ * TX MSDU for aggregation. Possible values are 0-31. When set to 0,
+ * it is decided by the hardware.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION = 65,
+
+ /* 8-bit unsigned value to configure the maximum number of subframes of
+ * RX MSDU for aggregation. Possible values are 0-31. When set to 0,
+ * it is decided by the hardware.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION = 66,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the LDPC capability of the device. When configured in
+ * the disconnected state, the updated configuration will be considered
+ * for the immediately following connection attempt. If this
+ * configuration is modified while the device is in the connected state,
+ * the LDPC TX will be updated with this configuration immediately,
+ * while the LDPC RX configuration update will take place starting from
+ * the subsequent association attempt.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC = 67,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the TX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * connection is formed with TX STBC enabled and if this configuration
+ * is disabled during that association, the TX will be impacted
+ * immediately. Further connection attempts will disable TX STBC.
+ * However, enabling the TX STBC for a connected session with disabled
+ * capability is not allowed and will fail.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC = 68,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the RX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * configuration is modified in the connected state, there will be no
+ * impact for the current association, but further connection attempts
+ * will use the updated configuration.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC = 69,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams. When configured in the disconnected
+ * state, the updated configuration will be considered for the
+ * immediately following connection attempt. If the NSS is updated after
+ * the connection, the updated NSS value is notified to the peer using
+ * the Operating Mode Notification/Spatial Multiplexing Power Save
+ * frame. The updated NSS value after the connection shall not be
+ * greater than the one negotiated during the connection. Any such
+ * higher value configuration shall be returned with a failure.
+ * Only symmetric NSS configuration (such as 2X2 or 1X1) can be done
+ * using this attribute. QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS and
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attributes shall be used to
+ * configure the asymmetric NSS configuration (such as 1X2).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70,
+ /* 8-bit unsigned value to trigger Optimized Power Management:
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT = 71,
+
+ /* 8-bit unsigned value. This attribute takes the QoS/access category
+ * value represented by the enum qca_wlan_ac_type and expects the driver
+ * to upgrade the UDP frames to this access category. The value of
+ * QCA_WLAN_AC_ALL is invalid for this attribute. This will override the
+ * DSCP value configured in the frame with the intention to only upgrade
+ * the access category. That said, it is not intended to downgrade the
+ * access category for the frames.
+ * Set the value to QCA_WLAN_AC_BK if the QoS upgrade needs to be
+ * disabled, as BK is of the lowest priority and an upgrade to it does
+ * not result in any changes for the frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE = 72,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for transmitting data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS = 73,
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for receiving data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS = 74,
+
+ /* 8-bit unsigned value to configure ANI setting type.
+ * See &enum qca_wlan_ani_setting for possible values.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING = 75,
+ /* 32-bit signed value to configure ANI level. This is used when
+ * ANI settings type is &QCA_WLAN_ANI_SETTING_FIXED.
+ * The set and get of ANI level with &QCA_WLAN_ANI_SETTING_AUTO
+ * is invalid, the driver will return a failure.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL = 76,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for transmitting the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The TX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute the driver
+ * will update the TX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS = 77,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for receiving the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The RX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute the driver
+ * will update the RX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS = 78,
+
+ /*
+ * 8-bit unsigned value. This attribute, when set, indicates whether the
+ * specified interface is the primary STA interface when there are more
+ * than one STA interfaces concurrently active.
+ *
+ * This configuration helps the firmware/hardware to support certain
+ * features (e.g., roaming) on this primary interface, if the same
+ * cannot be supported on the concurrent STA interfaces simultaneously.
+ *
+ * This configuration is only applicable for a single STA interface on
+ * a device and gives the priority for it only over other concurrent STA
+ * interfaces.
+ *
+ * If the device is a multi wiphy/soc, this configuration applies to a
+ * single STA interface across the wiphys.
+ *
+ * 1-Enable (is the primary STA), 0-Disable (is not the primary STA)
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY = 79,
+
+ /*
+ * 8-bit unsigned value. This attribute can be used to configure the
+ * driver to enable/disable FT-over-DS feature. Possible values for
+ * this attribute are 1-Enable and 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS = 80,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
};
+/* Compatibility defines for previously used incorrect enum
+ * qca_wlan_vendor_attr_config names. These values should not be used in any
+ * new implementation. */
+#define QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES
+#define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
+
+/**
+ * enum qca_wlan_ani_setting - ANI setting type
+ * @QCA_WLAN_ANI_SETTING_AUTO: Automatically determine ANI level
+ * @QCA_WLAN_ANI_SETTING_FIXED: Fix ANI level to the dBm parameter
+ */
+enum qca_wlan_ani_setting {
+ QCA_WLAN_ANI_SETTING_AUTO = 0,
+ QCA_WLAN_ANI_SETTING_FIXED = 1,
+};
+
/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
+ * Channel number on which Access Point should restart.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY: Optional (u32)
+ * Channel center frequency (MHz) on which the access point should restart.
*/
enum qca_wlan_vendor_attr_sap_config {
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
- /* 1 - reserved for QCA */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL = 1,
+
/* List of frequencies on which AP is expected to operate.
* This is irrespective of ACS configuration. This list is a priority
* based one and is looked for before the AP is created to ensure the
@@ -1898,6 +2509,7 @@ enum qca_wlan_vendor_attr_sap_config {
* the system.
*/
QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY = 3,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
@@ -1926,19 +2538,87 @@ enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
/**
* enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND: Required (u32)
+ * value to specify the GPIO command. Please refer to enum qca_gpio_cmd_type
+ * for the available values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM: Required (u32)
+ * value to specify the GPIO number.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG or %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE: Required (u32)
+ * value to specify the GPIO output level. Please refer to enum qca_gpio_value
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE: Optional (u32)
+ * value to specify the GPIO pull type. Please refer to enum qca_gpio_pull_type
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE: Optional (u32)
+ * value to specify the GPIO interrupt mode. Please refer to enum
+ * qca_gpio_interrupt_mode for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR: Optional (u32)
+ * value to specify the GPIO direction. Please refer to enum qca_gpio_direction
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG and
+ * %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG attribute is not present.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG
+ * attribute is present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG: Optional (u32)
+ * Value to specify the mux config. Meaning of a given value is dependent
+ * on the target chipset and GPIO pin. Must be of the range 0-15.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. Defaults to 0.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE: Optional (u32)
+ * Value to specify the drive, refer to enum qca_gpio_drive.
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. Defaults to QCA_WLAN_GPIO_DRIVE_2MA(0).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG: Optional (flag)
+ * Optional when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG. When present this attribute signals that all
+ * other parameters for the given GPIO will be obtained from internal
+ * configuration. Only %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM must be
+ * specified to indicate the GPIO pin being configured.
*/
enum qca_wlan_gpio_attr {
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
/* Unsigned 32-bit attribute for GPIO command */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND = 1,
/* Unsigned 32-bit attribute for GPIO PIN number to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM = 2,
/* Unsigned 32-bit attribute for GPIO value to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE = 3,
/* Unsigned 32-bit attribute for GPIO pull type */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE = 4,
/* Unsigned 32-bit attribute for GPIO interrupt mode */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE = 5,
+ /* Unsigned 32-bit attribute for GPIO direction to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR = 6,
+ /* Unsigned 32-bit attribute for GPIO mux config */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG = 7,
+ /* Unsigned 32-bit attribute for GPIO drive */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE = 8,
+ /* Flag attribute for using internal GPIO configuration */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG = 9,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
@@ -1947,6 +2627,97 @@ enum qca_wlan_gpio_attr {
};
/**
+ * enum gpio_cmd_type - GPIO configuration command type
+ * @QCA_WLAN_VENDOR_GPIO_CONFIG: Set GPIO configuration info
+ * @QCA_WLAN_VENDOR_GPIO_OUTPUT: Set GPIO output level
+ */
+enum qca_gpio_cmd_type {
+ QCA_WLAN_VENDOR_GPIO_CONFIG = 0,
+ QCA_WLAN_VENDOR_GPIO_OUTPUT = 1,
+};
+
+/**
+ * enum qca_gpio_pull_type - GPIO pull type
+ * @QCA_WLAN_GPIO_PULL_NONE: Set GPIO pull type to none
+ * @QCA_WLAN_GPIO_PULL_UP: Set GPIO pull up
+ * @QCA_WLAN_GPIO_PULL_DOWN: Set GPIO pull down
+ */
+enum qca_gpio_pull_type {
+ QCA_WLAN_GPIO_PULL_NONE = 0,
+ QCA_WLAN_GPIO_PULL_UP = 1,
+ QCA_WLAN_GPIO_PULL_DOWN = 2,
+ QCA_WLAN_GPIO_PULL_MAX,
+};
+
+/**
+ * enum qca_gpio_direction - GPIO direction
+ * @QCA_WLAN_GPIO_INPUT: Set GPIO as input mode
+ * @QCA_WLAN_GPIO_OUTPUT: Set GPIO as output mode
+ * @QCA_WLAN_GPIO_VALUE_MAX: Invalid value
+ */
+enum qca_gpio_direction {
+ QCA_WLAN_GPIO_INPUT = 0,
+ QCA_WLAN_GPIO_OUTPUT = 1,
+ QCA_WLAN_GPIO_DIR_MAX,
+};
+
+/**
+ * enum qca_gpio_value - GPIO Value
+ * @QCA_WLAN_GPIO_LEVEL_LOW: set gpio output level to low
+ * @QCA_WLAN_GPIO_LEVEL_HIGH: set gpio output level to high
+ * @QCA_WLAN_GPIO_LEVEL_MAX: Invalid value
+ */
+enum qca_gpio_value {
+ QCA_WLAN_GPIO_LEVEL_LOW = 0,
+ QCA_WLAN_GPIO_LEVEL_HIGH = 1,
+ QCA_WLAN_GPIO_LEVEL_MAX,
+};
+
+/**
+ * enum gpio_interrupt_mode - GPIO interrupt mode
+ * @QCA_WLAN_GPIO_INTMODE_DISABLE: Disable interrupt trigger
+ * @QCA_WLAN_GPIO_INTMODE_RISING_EDGE: Interrupt with GPIO rising edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_FALLING_EDGE: Interrupt with GPIO falling edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_BOTH_EDGE: Interrupt with GPIO both edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_LOW: Interrupt with GPIO level low trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH: Interrupt with GPIO level high trigger
+ * @QCA_WLAN_GPIO_INTMODE_MAX: Invalid value
+ */
+enum qca_gpio_interrupt_mode {
+ QCA_WLAN_GPIO_INTMODE_DISABLE = 0,
+ QCA_WLAN_GPIO_INTMODE_RISING_EDGE = 1,
+ QCA_WLAN_GPIO_INTMODE_FALLING_EDGE = 2,
+ QCA_WLAN_GPIO_INTMODE_BOTH_EDGE = 3,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_LOW = 4,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH = 5,
+ QCA_WLAN_GPIO_INTMODE_MAX,
+};
+
+/**
+ * enum qca_gpio_drive - GPIO drive
+ * @QCA_WLAN_GPIO_DRIVE_2MA: drive 2MA
+ * @QCA_WLAN_GPIO_DRIVE_4MA: drive 4MA
+ * @QCA_WLAN_GPIO_DRIVE_6MA: drive 6MA
+ * @QCA_WLAN_GPIO_DRIVE_8MA: drive 8MA
+ * @QCA_WLAN_GPIO_DRIVE_10MA: drive 10MA
+ * @QCA_WLAN_GPIO_DRIVE_12MA: drive 12MA
+ * @QCA_WLAN_GPIO_DRIVE_14MA: drive 14MA
+ * @QCA_WLAN_GPIO_DRIVE_16MA: drive 16MA
+ * @QCA_WLAN_GPIO_DRIVE_MAX: invalid GPIO drive
+ */
+enum qca_gpio_drive {
+ QCA_WLAN_GPIO_DRIVE_2MA = 0,
+ QCA_WLAN_GPIO_DRIVE_4MA = 1,
+ QCA_WLAN_GPIO_DRIVE_6MA = 2,
+ QCA_WLAN_GPIO_DRIVE_8MA = 3,
+ QCA_WLAN_GPIO_DRIVE_10MA = 4,
+ QCA_WLAN_GPIO_DRIVE_12MA = 5,
+ QCA_WLAN_GPIO_DRIVE_14MA = 6,
+ QCA_WLAN_GPIO_DRIVE_16MA = 7,
+ QCA_WLAN_GPIO_DRIVE_MAX,
+};
+
+/**
* qca_wlan_set_qdepth_thresh_attr - Parameters for setting
* MSDUQ depth threshold per peer per tid in the target
*
@@ -1977,6 +2748,54 @@ enum qca_wlan_set_qdepth_thresh_attr {
};
/**
+ * enum qca_acs_dfs_mode - Defines different types of DFS channel
+ * configurations for ACS operation.
+ *
+ * @QCA_ACS_DFS_MODE_NONE: Refer to invalid DFS mode
+ * @QCA_ACS_DFS_MODE_ENABLE: Consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DISABLE: Do not consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in ACS operation
+ */
+enum qca_acs_dfs_mode {
+ QCA_ACS_DFS_MODE_NONE = 0,
+ QCA_ACS_DFS_MODE_ENABLE = 1,
+ QCA_ACS_DFS_MODE_DISABLE = 2,
+ QCA_ACS_DFS_MODE_DEPRIORITIZE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_acs_config - Defines Configuration attributes
+ * used by the vendor command QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Required (u8)
+ * DFS mode for ACS operation from enum qca_acs_dfs_mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: Required (u8)
+ * channel number hint for ACS operation, if valid channel is specified then
+ * ACS operation gives priority to this channel.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT: Required (u32).
+ * Channel center frequency (MHz) hint for ACS operation, if a valid center
+ * frequency is specified, ACS operation gives priority to this channel.
+ */
+enum qca_wlan_vendor_attr_acs_config {
+ QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT = 3,
+
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
*/
enum qca_wlan_vendor_attr_get_hw_capability {
@@ -2986,7 +3805,7 @@ enum qca_wlan_vendor_attr_ll_stats_results {
QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS = 66,
/* Signifies the nested list of channel attributes
- * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_*
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_*
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
@@ -3048,6 +3867,21 @@ enum qca_wlan_vendor_attr_ll_stats_results {
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is transmitting on this channel. This attribute will be nested
+ * within QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME = 84,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is receiving all 802.11 frames intended for this device on this
+ * channel. This attribute will be nested within
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME = 85,
+ /* u8 value representing the channel load percentage. Possible values
+ * are 0-100.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -3359,6 +4193,593 @@ enum qca_wlan_vendor_attr_logger_results {
QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
};
+/**
+ * enum qca_scan_freq_list_type: Frequency list types
+ *
+ * @QCA_PREFERRED_SCAN_FREQ_LIST: The driver shall use the scan frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a preferred frequency list for roaming.
+ *
+ * @QCA_SPECIFIC_SCAN_FREQ_LIST: The driver shall use the frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a specific frequency list for roaming.
+ */
+enum qca_scan_freq_list_type {
+ QCA_PREFERRED_SCAN_FREQ_LIST = 1,
+ QCA_SPECIFIC_SCAN_FREQ_LIST = 2,
+};
+
+/**
+ * enum qca_vendor_attr_scan_freq_list_scheme: Frequency list scheme
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST: Nested attribute of u32 values
+ * List of frequencies in MHz to be considered for a roam scan.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE: Unsigned 32-bit value.
+ * Type of frequency list scheme being configured/gotten as defined by the
+ * enum qca_scan_freq_list_type.
+ */
+enum qca_vendor_attr_scan_freq_list_scheme {
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST = 1,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE = 2,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX =
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_roam_scan_scheme: Scan scheme
+ *
+ * @QCA_ROAM_SCAN_SCHEME_NO_SCAN: No frequencies specified to scan.
+ * Indicates the driver to not scan on a Roam Trigger scenario, but
+ * disconnect. E.g., on a BTM request from the AP the driver/firmware shall
+ * disconnect from the current connected AP by notifying a failure
+ * code in the BTM response.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN: Indicates the driver/firmware to
+ * trigger partial frequency scans. These frequencies are the ones learned
+ * or maintained by the driver based on the probability of finding the
+ * BSSIDs in the ESS for which the roaming is triggered.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_FULL_SCAN: Indicates the driver/firmware to
+ * trigger the scan on all the valid frequencies to find better
+ * candidates to roam.
+ */
+enum qca_roam_scan_scheme {
+ QCA_ROAM_SCAN_SCHEME_NO_SCAN = 0,
+ QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN = 1,
+ QCA_ROAM_SCAN_SCHEME_FULL_SCAN = 2,
+};
+
+/*
+ * enum qca_vendor_roam_triggers: Bitmap of roaming triggers
+ *
+ * @QCA_ROAM_TRIGGER_REASON_PER: Set if the roam has to be triggered based on
+ * a bad packet error rates (PER).
+ * @QCA_ROAM_TRIGGER_REASON_BEACON_MISS: Set if the roam has to be triggered
+ * based on beacon misses from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_POOR_RSSI: Set if the roam has to be triggered
+ * due to poor RSSI of the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered
+ * upon finding a BSSID with a better RSSI than the connected BSSID.
+ * Here the RSSI of the current BSSID need not be poor.
+ * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered
+ * by triggering a periodic scan to find a better AP to roam.
+ * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered
+ * when the connected channel environment is too noisy/congested.
+ * @QCA_ROAM_TRIGGER_REASON_BTM: Set if the roam has to be triggered
+ * when BTM Request frame is received from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
+ * when the channel utilization is goes above the configured threshold.
+ * @QCA_ROAM_TRIGGER_REASON_USER_TRIGGER: Set if the roam has to be triggered
+ * based on the request from the user (space).
+ * @QCA_ROAM_TRIGGER_REASON_DEAUTH: Set if the roam has to be triggered when
+ * device receives Deauthentication/Disassociation frame from connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_IDLE: Set if the roam has to be triggered when the
+ * device is in idle state (no TX/RX) and suspend mode, if the current RSSI
+ * is determined to be a poor one.
+ * @QCA_ROAM_TRIGGER_REASON_TX_FAILURES: Set if the roam has to be triggered
+ * based on continuous TX Data frame failures to the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN: Set if the roam has to be triggered
+ * based on the scan results obtained from an external scan (not triggered
+ * to aim roaming).
+ *
+ * Set the corresponding roam trigger reason bit to consider it for roam
+ * trigger.
+ * Userspace can set multiple bits and send to the driver. The driver shall
+ * consider all of them to trigger/initiate a roam scan.
+ */
+enum qca_vendor_roam_triggers {
+ QCA_ROAM_TRIGGER_REASON_PER = 1 << 0,
+ QCA_ROAM_TRIGGER_REASON_BEACON_MISS = 1 << 1,
+ QCA_ROAM_TRIGGER_REASON_POOR_RSSI = 1 << 2,
+ QCA_ROAM_TRIGGER_REASON_BETTER_RSSI = 1 << 3,
+ QCA_ROAM_TRIGGER_REASON_PERIODIC = 1 << 4,
+ QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
+ QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
+ QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+ QCA_ROAM_TRIGGER_REASON_USER_TRIGGER = 1 << 8,
+ QCA_ROAM_TRIGGER_REASON_DEAUTH = 1 << 9,
+ QCA_ROAM_TRIGGER_REASON_IDLE = 1 << 10,
+ QCA_ROAM_TRIGGER_REASON_TX_FAILURES = 1 << 11,
+ QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN = 1 << 12,
+};
+
+/*
+ * enum qca_vendor_roam_fail_reasons: Defines the various roam
+ * fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED: Roam module in the firmware is not
+ * able to trigger the scan.
+ * @QCA_ROAM_FAIL_REASON_NO_AP_FOUND: No roamable APs found during roam scan.
+ * @QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND: No candidate APs found during roam
+ * scan.
+ * @QCA_ROAM_FAIL_REASON_HOST: Roam fail due to disconnect issued from host.
+ * @QCA_ROAM_FAIL_REASON_AUTH_SEND: Unable to send Authentication frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_RECV: Received Authentication frame with error
+ * status code.
+ * @QCA_ROAM_FAIL_REASON_NO_AUTH_RESP: Authentication frame not received.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_SEND: Unable to send Reassociation Request
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_RECV: Received Reassociation Response frame
+ * with error status code.
+ * @QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP: Reassociation Response frame not
+ * received.
+ * @QCA_ROAM_FAIL_REASON_SCAN_FAIL: Scan module not able to start scan.
+ * @QCA_ROAM_FAIL_REASON_AUTH_NO_ACK: No ACK is received for Authentication
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: Authentication frame is dropped
+ * internally before transmission.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK: No ACK is received for Reassociation
+ * Request frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: Reassociation Request frame is
+ * dropped internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT: EAPOL-Key M1 is not received and
+ * times out.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND: Unable to send EAPOL-Key M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: EAPOL-Key M2 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: No ACK is received for EAPOL-Key
+ * M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: EAPOL-Key M3 frame is not received.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND: Unable to send EAPOL-Key M4 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: EAPOL-Key M4 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: No ACK is received for EAPOL-Key M4
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS: Roam scan is not
+ * started for final beacon miss case.
+ * @QCA_ROAM_FAIL_REASON_DISCONNECT: Deauthentication or Disassociation frame
+ * received from the AP during roaming handoff.
+ * @QCA_ROAM_FAIL_REASON_RESUME_ABORT: Firmware roams to the AP when the Apps
+ * or host is suspended and gives the indication of the last roamed AP only
+ * when the Apps is resumed. If the Apps is resumed while the roaming is in
+ * progress, this ongoing roaming is aborted and the last roamed AP is
+ * indicated to host.
+ * @QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID: WPA3-SAE invalid PMKID.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: WPA3-SAE pre-authentication times
+ * out.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: WPA3-SAE pre-authentication fails.
+ */
+enum qca_vendor_roam_fail_reasons {
+ QCA_ROAM_FAIL_REASON_NONE = 0,
+ QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED = 1,
+ QCA_ROAM_FAIL_REASON_NO_AP_FOUND = 2,
+ QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND = 3,
+ QCA_ROAM_FAIL_REASON_HOST = 4,
+ QCA_ROAM_FAIL_REASON_AUTH_SEND = 5,
+ QCA_ROAM_FAIL_REASON_AUTH_RECV = 6,
+ QCA_ROAM_FAIL_REASON_NO_AUTH_RESP = 7,
+ QCA_ROAM_FAIL_REASON_REASSOC_SEND = 8,
+ QCA_ROAM_FAIL_REASON_REASSOC_RECV = 9,
+ QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP = 10,
+ QCA_ROAM_FAIL_REASON_SCAN_FAIL = 11,
+ QCA_ROAM_FAIL_REASON_AUTH_NO_ACK = 12,
+ QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP = 13,
+ QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK = 14,
+ QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP = 15,
+ QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT = 16,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND = 17,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP = 18,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK = 19,
+ QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT = 20,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND = 21,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP = 22,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK = 23,
+ QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS = 24,
+ QCA_ROAM_FAIL_REASON_DISCONNECT = 25,
+ QCA_ROAM_FAIL_REASON_RESUME_ABORT = 26,
+ QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29,
+};
+
+/*
+ * enum qca_vendor_roam_invoke_fail_reasons: Defines the various roam
+ * invoke fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_INVOKE_STATUS_IFACE_INVALID: Invalid interface ID is passed
+ * in roam invoke command.
+ * @QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE: Roam offload in firmware is not
+ * enabled.
+ * @QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID: Connected AP profile SSID
+ * length is invalid.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW: Firmware internal roaming is already
+ * in progress.
+ * @QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP: Host sends the Beacon/Probe Response
+ * of the AP in the roam invoke command to firmware. This reason is sent by the
+ * firmware when the given AP is configured to be ignored or SSID/security
+ * does not match.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL: Roam handoff failed because of
+ * firmware internal reasons.
+ * @QCA_ROAM_INVOKE_STATUS_DISALLOW: Roam invoke trigger is not enabled.
+ * @QCA_ROAM_INVOKE_STATUS_SCAN_FAIL: Scan start fail for roam invoke.
+ * @QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL: Roam handoff start fail.
+ * @QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS: Roam invoke parameters are invalid.
+ * @QCA_ROAM_INVOKE_STATUS_NO_CAND_AP: No candidate AP found to roam to.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_FAIL: Roam handoff failed.
+ */
+enum qca_vendor_roam_invoke_fail_reasons {
+ QCA_ROAM_INVOKE_STATUS_NONE = 0,
+ QCA_ROAM_INVOKE_STATUS_IFACE_INVALID = 1,
+ QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE = 2,
+ QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID = 3,
+ QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW = 4,
+ QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP = 5,
+ QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL = 6,
+ QCA_ROAM_INVOKE_STATUS_DISALLOW = 7,
+ QCA_ROAM_INVOKE_STATUS_SCAN_FAIL = 8,
+ QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL = 9,
+ QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS = 10,
+ QCA_ROAM_INVOKE_STATUS_NO_CAND_AP = 11,
+ QCA_ROAM_INVOKE_STATUS_ROAM_FAIL = 12,
+
+};
+
+/**
+ * enum qca_vendor_attr_roam_candidate_selection_criteria:
+ *
+ * Each attribute carries a weightage in percentage (%).
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI: Unsigned 8-bit value.
+ * Represents the weightage to be given for the RSSI selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE: Unsigned 8-bit value.
+ * Represents the weightage to be given for the rate selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band width selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS: Unsigned 8-bit value.
+ * Represents the weightage to be given for the NSS selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION: Unsigned 8-bit value.
+ * Represents the weightage to be given for the channel congestion
+ * selection criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING: Unsigned 8-bit value.
+ * Represents the weightage to be given for the beamforming selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN: Unsigned 8-bit value.
+ * Represents the weightage to be given for the OCE selection
+ * criteria among other parameters.
+ */
+enum qca_vendor_attr_roam_candidate_selection_criteria {
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI = 1,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE = 2,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW = 3,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND = 4,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS = 5,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION = 6,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING = 7,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX =
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
+ * The following attributes are used to set/get/clear the respective
+ * configurations to/from the driver.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable values to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ENABLE: Unsigned 8-bit value.
+ * Signifies to enable/disable roam control in driver.
+ * 1-enable, 0-disable
+ * Enable: Mandates the driver to do the further roams using the
+ * configuration parameters set through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET.
+ * Disable: Disables the driver/firmware roaming triggered through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET. Further roaming is
+ * expected to continue with the default configurations.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_STATUS: Unsigned 8-bit value.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET.
+ * Roam control status is obtained through this attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CLEAR_ALL: Flag attribute to indicate the
+ * complete config set through QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET
+ * is to be cleared in the driver.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR
+ * and shall be ignored if used with other sub commands.
+ * If this attribute is specified along with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR, the driver shall ignore
+ * all other attributes, if there are any.
+ * If this attribute is not specified when the subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR is sent, the driver shall
+ * clear the data corresponding to the attributes specified.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME: Nested attribute to carry the
+ * list of frequencies and its type, represented by
+ * enum qca_vendor_attr_scan_freq_list_scheme.
+ * Frequency list and its type are mandatory for this attribute to set
+ * the frequencies.
+ * Frequency type is mandatory for this attribute to get the frequencies
+ * and the frequency list is obtained through
+ * QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST.
+ * Frequency list type is mandatory for this attribute to clear the
+ * frequencies.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of scan period in seconds to set.
+ * The value of scan period is obtained with the same attribute for get.
+ * Clears the scan period in the driver when specified with clear command.
+ * Scan period is the idle time in seconds between each subsequent
+ * channel scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of full scan period in seconds to set.
+ * The value of full scan period is obtained with the same attribute for
+ * get.
+ * Clears the full scan period in the driver when specified with clear
+ * command. Full scan period is the idle period in seconds between two
+ * successive full channel roam scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * The driver shall enable roaming by enabling corresponding roam triggers
+ * based on the trigger bits sent with this attribute.
+ * If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ * The bitmap configured is obtained with the same attribute for get.
+ * Clears the bitmap configured in driver when specified with clear
+ * command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA: Nested attribute signifying the
+ * weightage in percentage (%) to be given for each selection criteria.
+ * Different roam candidate selection criteria are represented by
+ * enum qca_vendor_attr_roam_candidate_selection_criteria.
+ * The driver shall select the roam candidate based on corresponding
+ * candidate selection scores sent.
+ *
+ * An empty nested attribute is used to indicate that no specific
+ * preference score/criteria is configured (i.e., to disable this mechanism
+ * in the set case and to show that the mechanism is disabled in the get
+ * case).
+ *
+ * Userspace can send multiple attributes out of this enum to the driver.
+ * Since this attribute represents the weight/percentage of preference for
+ * the respective selection criteria, it is preferred to configure 100%
+ * total weightage. The value in each attribute or cumulative weight of the
+ * values in all the nested attributes should not exceed 100%. The driver
+ * shall reject such configuration.
+ *
+ * If the weights configured through this attribute are less than 100%,
+ * the driver shall honor the weights (x%) passed for the corresponding
+ * selection criteria and choose/distribute rest of the weight (100-x)%
+ * for the other selection criteria, based on its internal logic.
+ *
+ * The selection criteria configured is obtained with the same
+ * attribute for get.
+ *
+ * Clears the selection criteria configured in the driver when specified
+ * with clear command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME: Unsigned 32-bit value.
+ * Represents value of the scan frequency scheme from enum
+ * qca_roam_scan_scheme.
+ * It's an optional attribute. If this attribute is not configured, the
+ * driver shall proceed with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the current connected AP, indicating
+ * the driver to trigger roam only when the current connected AP's RSSI
+ * is less than this threshold.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the candidate AP, indicating
+ * the driver to trigger roam only to the candidate AP with RSSI
+ * better than this threshold. If RSSI thresholds for candidate APs found
+ * in the 2.4 GHz, 5 GHz, and 6 GHz bands are configured separately using
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ,
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ, and/or
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ, those values will
+ * take precedence over the value configured using the
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_USER_REASON: Unsigned 32-bit value. Represents the
+ * user defined reason code to be sent to the AP in response to AP's
+ * request to trigger the roam if the roaming cannot be triggered.
+ * Applies to all the scenarios of AP assisted roaming (e.g., BTM).
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * Represents the roam triggers for which the specific scan scheme from
+ * enum qca_roam_scan_scheme has to be applied.
+ * It's an optional attribute. If this attribute is not configured, but
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is specified, the scan scheme
+ * specified through QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is applicable for
+ * all the roams.
+ * If both QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME and
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS are not specified, the
+ * driver shall proceed with the default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ: Signed 32-bit value
+ * in dBm, signifying the RSSI threshold of the candidate AP found in the
+ * 2.4 GHz band. The driver/firmware shall trigger roaming to the candidate
+ * AP found in the 2.4 GHz band only if its RSSI value is better than this
+ * threshold. Optional attribute. If this attribute is not included, the
+ * threshold value specified by the
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD attribute shall be used.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ: Signed 32-bit value in
+ * dBm, signifying the RSSI threshold of the candidate AP found in the 5
+ * GHz band. The driver/firmware shall trigger roaming to the candidate AP
+ * found in the 5 GHz band only if its RSSI value is better than this
+ * threshold. Optional attribute. If this attribute is not included, the
+ * threshold value specified by tge
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD attribute shall be used.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ: Signed 32-bit value in
+ * dBm, signifying the RSSI threshold of the candidate AP found in the 6
+ * GHz band. The driver/firmware shall trigger roaming to the candidate AP
+ * found in the 6 GHz band only if its RSSI value is better than this
+ * threshold. Optional attribute. If this attribute is not included, the
+ * threshold value specified by the
+ * QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD attribute shall be used.
+ *
+ */
+enum qca_vendor_attr_roam_control {
+ QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
+ QCA_ATTR_ROAM_CONTROL_STATUS = 2,
+ QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3,
+ QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4,
+ QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5,
+ QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
+ QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
+ QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME = 9,
+ QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD = 10,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD = 11,
+ QCA_ATTR_ROAM_CONTROL_USER_REASON = 12,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS = 13,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ = 14,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ = 15,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ = 16,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_MAX =
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roaming_config_params: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: Unsigned 32-bit value.
+ * Represents the different roam sub commands referred by
+ * enum qca_wlan_vendor_roaming_subcmd.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Unsigned 32-bit value.
+ * Represents the Request ID for the specific set of commands.
+ * This also helps to map specific set of commands to the respective
+ * ID / client. e.g., helps to identify the user entity configuring the
+ * ignored BSSIDs and accordingly clear the respective ones with the
+ * matching ID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
+ * 32-bit value.Represents the number of whitelist SSIDs configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute
+ * to carry the list of Whitelist SSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute,
+ * 0..32 octets). Represents the white list SSID. Whitelist SSIDs
+ * represent the list of SSIDs to which the firmware/driver can consider
+ * to roam to.
+ *
+ * The following PARAM_A_BAND_XX attributes are applied to 5GHz BSSIDs when
+ * comparing with a 2.4GHz BSSID. They are not applied when comparing two
+ * 5GHz BSSIDs.The following attributes are set through the Roaming SUBCMD -
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold above which 5GHz RSSI is favored.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold below which 5GHz RSSI is penalized.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is boosted.
+ * boost=(RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is penalized.
+ * penalty=(5GHz_penalty_threshold-RSSI_measured)*5GHz_penalty_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: Unsigned 32-bit
+ * value, maximum boost that can be applied to a 5GHz RSSI.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: Unsigned 32-bit
+ * value, boost applied to current BSSID to ensure the currently
+ * associated BSSID is favored so as to prevent ping-pong situations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: Signed 32-bit
+ * value, RSSI below which "Alert" roam is enabled.
+ * "Alert" mode roaming - firmware is "urgently" hunting for another BSSID
+ * because the RSSI is low, or because many successive beacons have been
+ * lost or other bad link conditions.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit
+ * value. 1-Enable, 0-Disable. Represents "Lazy" mode, where
+ * firmware is hunting for a better BSSID or white listed SSID even though
+ * the RSSI of the link is good. The parameters enabling the roaming are
+ * configured through the PARAM_A_BAND_XX attrbutes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: Nested attribute,
+ * represents the BSSIDs preferred over others while evaluating them
+ * for the roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: Unsigned
+ * 32-bit value. Represents the number of preferred BSSIDs set.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: 6-byte MAC
+ * address representing the BSSID to be preferred.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: Signed
+ * 32-bit value, representing the modifier to be applied to the RSSI of
+ * the BSSID for the purpose of comparing it with other roam candidate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
+ * represents the BSSIDs to get ignored for roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
+ * 32-bit value, represents the number of ignored BSSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
+ * address representing the ignored BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
+ * indicates this request to ignore the BSSID as a hint to the driver. The
+ * driver can select this BSSID in the worst case (when no other BSSIDs are
+ * better).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
+ * set/get/clear the roam control config as
+ * defined @enum qca_vendor_attr_roam_control.
+ */
enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
@@ -3388,13 +4809,15 @@ enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
- /* Attribute for set_blacklist bssid params */
+ /* Attribute for setting ignored BSSID parameters */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
- /* Flag attribute indicates this BSSID blacklist as a hint */
+ /* Flag attribute indicates this entry as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
@@ -3402,22 +4825,63 @@ enum qca_wlan_vendor_attr_roaming_config_params {
};
/*
- * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
- */
-enum qca_wlan_vendor_attr_roam_subcmd {
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
-
- /* keep last */
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+ * enum qca_wlan_vendor_roaming_subcmd: Referred by
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to
+ * configure the white list SSIDs. These are configured through
+ * the following attributes.
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to
+ * configure the Roam params. These parameters are evaluated on the GScan
+ * results. Refers the attributes PARAM_A_BAND_XX above to configure the
+ * params.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: Sets the Lazy roam. Uses
+ * the attribute QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE
+ * to enable/disable Lazy roam.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: Sets the BSSID
+ * preference. Contains the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
+ * preference.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the list of BSSIDs
+ * to ignore in roaming decision. Uses
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to set the list.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
+ * roam control config to the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: Command to obtain the
+ * roam control config from driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable value to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: Command to clear the
+ * roam control config in the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * The driver shall continue with its default roaming behavior when data
+ * corresponding to an attribute is cleared.
+ */
+enum qca_wlan_vendor_roaming_subcmd {
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9,
};
enum qca_wlan_vendor_attr_gscan_config_params {
@@ -3785,8 +5249,8 @@ enum qca_wlan_vendor_attr_gscan_results {
/* Unsigned 32-bit value; a GSCAN Capabilities attribute.
* This is used to limit the maximum number of BSSIDs while sending
- * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
- * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
*/
QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
@@ -3888,6 +5352,44 @@ enum qca_wlan_vendor_acs_select_reason {
QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
/* Represents the reason that LTE co-exist in the current band. */
QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+ /* Represents the reason that generic, uncategorized interference has
+ * been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_GENERIC_INTERFERENCE,
+ /* Represents the reason that excessive 802.11 interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_80211_INTERFERENCE,
+ /* Represents the reason that generic Continuous Wave (CW) interference
+ * has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_CW_INTERFERENCE,
+ /* Represents the reason that Microwave Oven (MWO) interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_MWO_INTERFERENCE,
+ /* Represents the reason that generic Frequency-Hopping Spread Spectrum
+ * (FHSS) interference has been found in the current channel. This may
+ * include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_FHSS_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Frequency-Hopping
+ * Spread Spectrum (FHSS) interference has been found in the current
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_FHSS_INTERFERENCE,
+ /* Represents the reason that generic Wideband (WB) interference has
+ * been found in the current channel. This may include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_WB_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Wideband (WB)
+ * interference has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_WB_INTERFERENCE,
+ /* Represents the reason that Jammer interference has been found in the
+ * current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
};
/**
@@ -4011,9 +5513,9 @@ enum qca_wlan_vendor_channel_prop_flags_ext {
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC = 1 << 6,
/* Station only channel */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_HOSTAP = 1 << 7,
- /* DFS radar history for slave device (STA mode) */
+ /* DFS radar history for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_HISTORY_RADAR = 1 << 8,
- /* DFS CAC valid for slave device (STA mode) */
+ /* DFS CAC valid for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CAC_VALID = 1 << 9,
};
@@ -4055,6 +5557,46 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr {
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
+ /*
+ * VHT segment 0 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * should be used.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12,
+
+ /*
+ * VHT segment 1 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * should be considered.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -4155,9 +5697,100 @@ enum qca_wlan_vendor_attr_external_acs_event {
};
/**
- * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * enum qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
* in priority order as decided after ACS operation in userspace.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON: Required (u8).
+ * One of reason code from enum qca_wlan_vendor_acs_select_reason.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY: Required (u8).
+ * Primary channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY: Required (u8).
+ * Secondary channel number, required only for 160 and 80+80 MHz bandwidths.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0: Required (u8).
+ * VHT seg0 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1: Required (u8).
+ * VHT seg1 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH: Required (u8).
+ * Takes one of enum nl80211_chan_width values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY: Required (u32)
+ * Primary channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY: Required (u32)
+ * Secondary channel frequency in MHz used for HT 40 MHz channels.
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0: Required (u32)
+ * VHT seg0 channel frequency in MHz
+ * Note: If user-space application has no support of the 6GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1: Required (u32)
+ * VHT seg1 channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
*/
enum qca_wlan_vendor_attr_external_acs_channels {
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
@@ -4188,6 +5821,12 @@ enum qca_wlan_vendor_attr_external_acs_channels {
/* Channel width (u8). Takes one of enum nl80211_chan_width values. */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST = 9,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY = 10,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
@@ -4599,8 +6238,12 @@ enum qca_wlan_vendor_attr_spectral_scan {
* QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
* Center frequency (in MHz) of the span of interest or
* for convenience, center frequency (in MHz) of any channel
- * in the span of interest. If agile spectral scan is initiated
- * without setting a valid frequency it returns the error code
+ * in the span of interest. For 80+80 MHz agile spectral scan
+ * request it represents center frequency (in MHz) of the primary
+ * 80 MHz span or for convenience, center frequency (in MHz) of any
+ * channel in the primary 80 MHz span. If agile spectral scan is
+ * initiated without setting a valid frequency it returns the
+ * error code
* (QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED).
* u32 attribute.
*/
@@ -4627,6 +6270,20 @@ enum qca_wlan_vendor_attr_spectral_scan {
* 1-enable, 0-disable
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_BUFFER_DEBUG = 28,
+ /* This specifies the frequency span over which spectral scan would be
+ * carried out. Its value depends on the value of
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE and the relation is as
+ * follows.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL
+ * Not applicable. Spectral scan would happen in the operating span.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
+ * This attribute is applicable only for agile spectral scan
+ * requests in 80+80 MHz mode. It represents center frequency (in
+ * MHz) of the secondary 80 MHz span or for convenience, center
+ * frequency (in MHz) of any channel in the secondary 80 MHz span.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY_2 = 29,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -4705,8 +6362,38 @@ enum qca_wlan_vendor_attr_spectral_cap {
* u8 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
- /* Flag attribute to indicate agile spectral scan capability */
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 20/40/80 MHz modes.
+ */
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 160 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160 = 12,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 80+80 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80 = 13,
+ /* Number of spectral detectors used for scan in 20 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_20_MHZ = 14,
+ /* Number of spectral detectors used for scan in 40 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_40_MHZ = 15,
+ /* Number of spectral detectors used for scan in 80 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_80_MHZ = 16,
+ /* Number of spectral detectors used for scan in 160 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_160_MHZ = 17,
+ /* Number of spectral detectors used for scan in 80+80 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_80P80_MHZ = 18,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -4856,6 +6543,49 @@ enum qca_wlan_vendor_hang_reason {
QCA_WLAN_HANG_DXE_FAILURE = 12,
/* WMI pending commands exceed the maximum count */
QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13,
+ /* Timeout for peer STA connection accept command's response from the
+ * FW in AP mode. This command is triggered when a STA (peer) connects
+ * to AP (DUT).
+ */
+ QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT = 14,
+ /* Timeout for the AP connection accept command's response from the FW
+ * in STA mode. This command is triggered when the STA (DUT) connects
+ * to an AP (peer).
+ */
+ QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT = 15,
+ /* Timeout waiting for the response to the MAC HW mode change command
+ * sent to FW as a part of MAC mode switch among DBS (Dual Band
+ * Simultaneous), SCC (Single Channel Concurrency), and MCC (Multi
+ * Channel Concurrency) mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT = 16,
+ /* Timeout waiting for the response from FW to configure the MAC HW's
+ * mode. This operation is to configure the single/two MACs in either
+ * SCC/MCC/DBS mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT = 17,
+ /* Timeout waiting for response of VDEV start command from the FW */
+ QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT = 18,
+ /* Timeout waiting for response of VDEV restart command from the FW */
+ QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT = 19,
+ /* Timeout waiting for response of VDEV stop command from the FW */
+ QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT = 20,
+ /* Timeout waiting for response of VDEV delete command from the FW */
+ QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT = 21,
+ /* Timeout waiting for response of peer all delete request command to
+ * the FW on a specific VDEV.
+ */
+ QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22,
+ /* WMI sequence mismatch between WMI command and Tx completion */
+ QCA_WLAN_HANG_WMI_BUF_SEQUENCE_MISMATCH = 23,
+ /* Write to Device HAL register failed */
+ QCA_WLAN_HANG_REG_WRITE_FAILURE = 24,
+ /* No credit left to send the wow_wakeup_from_sleep to firmware */
+ QCA_WLAN_HANG_SUSPEND_NO_CREDIT = 25,
+ /* Bus failure */
+ QCA_WLAN_HANG_BUS_FAILURE = 26,
+ /* tasklet/credit latency found */
+ QCA_WLAN_HANG_TASKLET_CREDIT_LATENCY_DETECT = 27,
};
/**
@@ -4868,6 +6598,12 @@ enum qca_wlan_vendor_attr_hang {
* qca_wlan_vendor_hang_reason.
*/
QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1,
+ /* The binary blob data associated with the hang reason specified by
+ * QCA_WLAN_VENDOR_ATTR_HANG_REASON. This binary data is expected to
+ * contain the required dump to analyze the reason for the hang.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ */
+ QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA = 2,
QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_HANG_MAX =
@@ -4968,12 +6704,22 @@ enum qca_wlan_vendor_attr_rrop_info {
enum qca_wlan_vendor_attr_rtplinst {
QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
- /* Primary channel number (u8) */
+ /* Primary channel number (u8).
+ * Note: If both the driver and user space application support the
+ * 6 GHz band, this attribute is deprecated and
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY should be used. To
+ * maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY is still used if either the
+ * driver or user space application or both do not support the 6 GHz
+ * band.
+ */
QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1,
/* Representative Tx power in dBm (s32) with emphasis on throughput. */
QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2,
/* Representative Tx power in dBm (s32) with emphasis on range. */
QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3,
+ /* Primary channel center frequency (u32) in MHz */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY = 4,
QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
@@ -5505,6 +7251,30 @@ enum qca_wlan_vendor_attr_wake_stats {
};
/**
+ * enum qca_wlan_vendor_thermal_level - Defines various thermal levels
+ * configured by userspace to the driver/firmware.
+ * The values can be encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL or
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL attribute.
+ * The driver/firmware takes actions requested by userspace such as throttling
+ * wifi TX etc. in order to mitigate high temperature.
+ *
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: Stop/clear all throttling actions.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: Throttle TX lightly.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: Throttle TX moderately.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: Throttle TX severely.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: Critical thermal level reached.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: Emergency thermal level reached.
+ */
+enum qca_wlan_vendor_thermal_level {
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE = 0,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT = 1,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE = 2,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE = 3,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL = 4,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY = 5,
+};
+
+/**
* enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set
* cmd value. Used for NL attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
@@ -5517,6 +7287,22 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+ /* Userspace uses this attribute to configure thermal level to the
+ * driver/firmware, or get thermal level from the driver/firmware.
+ * Used in request or response, u32 attribute,
+ * possible values are defined in enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
+ /* Userspace uses this attribute to configure the time in which the
+ * driver/firmware should complete applying settings it received from
+ * userspace with QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL
+ * command type. Used in request, u32 attribute, value is in
+ * milliseconds. A value of zero indicates to apply the settings
+ * immediately. The driver/firmware can delay applying the configured
+ * thermal settings within the time specified in this attribute if
+ * there is any critical ongoing operation.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
@@ -5540,12 +7326,19 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* suspend action.
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
* resume action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
+ * the driver/firmware.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL: Request to get the current
+ * thermal level from the driver/firmware. The driver should respond with a
+ * thermal level defined in enum qca_wlan_vendor_thermal_level.
*/
enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL,
};
/**
@@ -5628,6 +7421,11 @@ enum qca_wlan_vendor_attr_thermal_event {
* NLA_FLAG attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+ /* Thermal level from the driver.
+ * u32 attribute. Possible values are defined in
+ * enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
@@ -5794,6 +7592,21 @@ enum qca_wlan_he_om_ctrl_ch_bw {
};
/**
+ * enum qca_wlan_keep_alive_data_type - Keep alive data type configuration
+ *
+ * Indicates the frame types to use for keep alive data.
+ *
+ * @QCA_WLAN_KEEP_ALIVE_DEFAULT: Driver default type used for keep alive.
+ * @QCA_WLAN_KEEP_ALIVE_DATA: Data frame type for keep alive.
+ * @QCA_WLAN_KEEP_ALIVE_MGMT: Management frame type for keep alive.
+ */
+enum qca_wlan_keep_alive_data_type {
+ QCA_WLAN_KEEP_ALIVE_DEFAULT = 0,
+ QCA_WLAN_KEEP_ALIVE_DATA = 1,
+ QCA_WLAN_KEEP_ALIVE_MGMT = 2,
+};
+
+/**
* enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
* HE operating mode control transmit request. These attributes are
* sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
@@ -5841,6 +7654,72 @@ enum qca_wlan_vendor_attr_he_omi_tx {
QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
};
+ /**
+ * enum qca_wlan_vendor_phy_mode - Different PHY modes
+ * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE.
+ *
+ * @QCA_WLAN_VENDOR_PHY_MODE_AUTO: autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: 2.4 GHz 802.11b/g/n/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: 5 GHz 802.11a/n/ac/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_11A: 5 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11B: 2.4 GHz, CCK
+ * @QCA_WLAN_VENDOR_PHY_MODE_11G: 2.4 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AGN: Support 802.11n in both 2.4 GHz and 5 GHz
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: 2.4 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: 2.4 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: 2.4 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: 2.4 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: 5 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: 5 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: 5 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: 5 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: 5 GHz, VHT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: 5 GHz, VHT40 (Ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: 5 GHz VHT40 (Ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: 5 GHz, VHT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: 5 GHz, VHT80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: 5 GHz, VHT80+80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: 5 GHz, VHT160
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: HE20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: HE40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: HE40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: HE40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: HE80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: HE 80P80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: HE160
+ */
+enum qca_wlan_vendor_phy_mode {
+ QCA_WLAN_VENDOR_PHY_MODE_AUTO = 0,
+ QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO = 1,
+ QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO = 2,
+ QCA_WLAN_VENDOR_PHY_MODE_11A = 3,
+ QCA_WLAN_VENDOR_PHY_MODE_11B = 4,
+ QCA_WLAN_VENDOR_PHY_MODE_11G = 5,
+ QCA_WLAN_VENDOR_PHY_MODE_11AGN = 6,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20 = 7,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS = 8,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS = 9,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40 = 10,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20 = 11,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS = 12,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS = 13,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40 = 14,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20 = 15,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS = 16,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS = 17,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40 = 18,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80 = 19,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80 = 20,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160 = 21,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20 = 22,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40 = 23,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS = 24,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS = 25,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80 = 26,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80 = 27,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160 = 28,
+};
+
/* Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
*/
@@ -6124,6 +8003,161 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
+ /* 8-bit unsigned value to configure protection for Management
+ * frames when PMF is enabled for the association.
+ * This attribute is used to configure the testbed device.
+ * 0-use the correct key, 1-use an incorrect key, 2-disable protection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PMF_PROTECTION = 38,
+
+ /* Flag attribute to inject Disassociation frame to the connected AP.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISASSOC_TX = 39,
+
+ /* 8-bit unsigned value to configure an override for the RSNXE Used
+ * subfield in the MIC control field of the FTE in FT Reassociation
+ * Request frame.
+ * 0 - Default behavior, 1 - override with 1, 2 - override with 0.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FT_REASSOCREQ_RSNXE_USED = 40,
+
+ /* 8-bit unsigned value to configure the driver to ignore CSA (Channel
+ * Switch Announcement) when STA is in connected state.
+ * 0 - Default behavior, 1 - Ignore CSA.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_CSA = 41,
+
+ /* Nested attribute values required to configure OCI (Operating Channel
+ * Information). Attributes defined in enum
+ * qca_wlan_vendor_attr_oci_override are nested within this attribute.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE = 42,
+
+ /* 8-bit unsigned value to configure the driver/firmware to ignore SA
+ * Query timeout. If this configuration is enabled STA shall not send
+ * Deauthentication frmae when SA Query times out (mainly, after a
+ * channel switch when OCV is enabled).
+ * 0 - Default behavior, 1 - Ignore SA Query timeout.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_SA_QUERY_TIMEOUT = 43,
+
+ /* 8-bit unsigned value to configure the driver/firmware to start or
+ * stop transmitting FILS discovery frames.
+ * 0 - Stop transmitting FILS discovery frames
+ * 1 - Start transmitting FILS discovery frames
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only in AP mode and the
+ * configuration is valid until AP restart.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FILS_DISCOVERY_FRAMES_TX = 44,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable full bandwidth UL MU-MIMO subfield in the HE PHY capabilities
+ * information field.
+ * 0 - Disable full bandwidth UL MU-MIMO subfield
+ * 1 - Enable full bandwidth UL MU-MIMO subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FULL_BW_UL_MU_MIMO = 45,
+
+ /* 16-bit unsigned value to configure the driver with a specific BSS
+ * max idle period to advertise in the BSS Max Idle Period element
+ * (IEEE Std 802.11-2016, 9.4.2.79) in (Re)Association Request frames.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD = 46,
+
+ /* 8-bit unsigned value to configure the driver to use only RU 242 tone
+ * for data transmission.
+ * 0 - Default behavior, 1 - Configure RU 242 tone for data Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RU_242_TONE_TX = 47,
+
+ /* 8-bit unsigned value to configure the driver to disable data and
+ * management response frame transmission to test the BSS max idle
+ * feature.
+ * 0 - Default behavior, 1 - Disable data and management response Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_DATA_MGMT_RSP_TX = 48,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable Punctured Preamble Rx subfield in the HE PHY capabilities
+ * information field.
+ * 0 - Disable Punctured Preamble Rx subfield
+ * 1 - Enable Punctured Preamble Rx subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX = 49,
+
+ /* 8-bit unsigned value to configure the driver to ignore the SAE H2E
+ * requirement mismatch for 6 GHz connection.
+ * 0 - Default behavior, 1 - Ignore SAE H2E requirement mismatch.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_H2E_RSNXE = 50,
+
+ /* 8-bit unsigned value to configure the driver to allow 6 GHz
+ * connection with all security modes.
+ * 0 - Default behavior, 1 - Allow 6 GHz connection with all security
+ * modes.
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_6GHZ_SECURITY_TEST_MODE = 51,
+
+ /* 8-bit unsigned value to configure the driver to transmit data with
+ * ER SU PPDU type.
+ *
+ * 0 - Default behavior, 1 - Enable ER SU PPDU type TX.
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ER_SU_PPDU_TYPE = 52,
+
+ /* 8-bit unsigned value to configure the driver to use Data or
+ * Management frame type for keep alive data.
+ * Uses enum qca_wlan_keep_alive_data_type values.
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_KEEP_ALIVE_FRAME_TYPE = 53,
+
+ /* 8-bit unsigned value to configure the driver to use scan request
+ * BSSID value in Probe Request frame RA(A1) during the scan. The
+ * driver saves this configuration and applies this setting to all user
+ * space scan requests until the setting is cleared. If this
+ * configuration is set, the driver uses the BSSID value from the scan
+ * request to set the RA(A1) in the Probe Request frames during the
+ * scan.
+ *
+ * 0 - Default behavior uses the broadcast RA in Probe Request frames.
+ * 1 - Uses the scan request BSSID in RA in Probe Request frames.
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_USE_BSSID_IN_PROBE_REQ_RA = 54,
+
+ /* 8-bit unsigned value to configure the driver to enable/disable the
+ * BSS max idle period support.
+ *
+ * 0 - Disable the BSS max idle support.
+ * 1 - Enable the BSS max idle support.
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD_ENABLE = 55,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -6131,6 +8165,111 @@ enum qca_wlan_vendor_attr_wifi_test_config {
};
/**
+ * enum qca_wlan_twt_operation - Operation of the config TWT request
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION.
+ * The response for the respective operations can be either synchronous or
+ * asynchronous (wherever specified). If synchronous, the response to this
+ * operation is obtained in the corresponding vendor command reply to the user
+ * space. For the asynchronous case the response is obtained as an event with
+ * the same operation type.
+ *
+ * Drivers shall support either of these modes but not both simultaneously.
+ * This support for asynchronous mode is advertised through the flag
+ * QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT. If this flag is not advertised,
+ * the driver shall support synchronous mode.
+ *
+ * @QCA_WLAN_TWT_SET: Setup a TWT session. Required parameters are configured
+ * through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Depending upon the
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability, this is either a
+ * synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET: Get the configured TWT parameters. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. This is a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_TERMINATE: Terminate the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * This terminate can either get triggered by the user space or can as well be
+ * a notification from the firmware if it initiates a terminate.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * the request from user space can either be a synchronous or asynchronous
+ * operation.
+ *
+ * @QCA_WLAN_TWT_SUSPEND: Suspend the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_RESUME: Resume the TWT session. Required parameters are
+ * configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_resume. Valid only after the TWT session is setup.
+ * This can as well be a notification from the firmware on a QCA_WLAN_TWT_NUDGE
+ * request. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_NUDGE: Suspend and resume the TWT session. TWT nudge is a
+ * combination of suspend and resume in a single request. Required parameters
+ * are configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the
+ * enum qca_wlan_vendor_attr_twt_nudge. Valid only after the TWT session is
+ * setup. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_STATS: Get the TWT session traffic statistics information.
+ * Refers the enum qca_wlan_vendor_attr_twt_stats. Valid only after the TWT
+ * session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_CLEAR_STATS: Clear TWT session traffic statistics information.
+ * Valid only after the TWT session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_CAPABILITIES: Get TWT capabilities of this device and its
+ * peer. Refers the enum qca_wlan_vendor_attr_twt_capability. It's a synchronous
+ * operation.
+ *
+ * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmare is
+ * ready for a new TWT session setup after it issued a TWT teardown.
+ */
+enum qca_wlan_twt_operation {
+ QCA_WLAN_TWT_SET = 0,
+ QCA_WLAN_TWT_GET = 1,
+ QCA_WLAN_TWT_TERMINATE = 2,
+ QCA_WLAN_TWT_SUSPEND = 3,
+ QCA_WLAN_TWT_RESUME = 4,
+ QCA_WLAN_TWT_NUDGE = 5,
+ QCA_WLAN_TWT_GET_STATS = 6,
+ QCA_WLAN_TWT_CLEAR_STATS = 7,
+ QCA_WLAN_TWT_GET_CAPABILITIES = 8,
+ QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_twt: Defines attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION: u8 attribute. Specify the TWT
+ * operation of this request. Possible values are defined in enum
+ * qca_wlan_twt_operation. The parameters for the respective operation is
+ * specified through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS: Nested attribute representing the
+ * parameters configured for TWT. These parameters are represented by
+ * enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume,
+ * or enum qca_wlan_vendor_attr_twt_stats based on the operation.
+ */
+enum qca_wlan_vendor_attr_config_twt {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
* QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
* The user can add/delete the filter by specifying the BSSID/STA MAC address in
@@ -6278,10 +8417,24 @@ enum qca_wlan_vendor_attr_nan_params {
};
/**
+ * qca_wlan_twt_setup_state: Represents the TWT session states.
+ *
+ * QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: TWT session not established.
+ * QCA_WLAN_TWT_SETUP_STATE_ACTIVE: TWT session is active.
+ * QCA_WLAN_TWT_SETUP_STATE_SUSPEND: TWT session is in suspended state.
+ */
+enum qca_wlan_twt_setup_state {
+ QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED = 0,
+ QCA_WLAN_TWT_SETUP_STATE_ACTIVE = 1,
+ QCA_WLAN_TWT_SETUP_STATE_SUSPEND = 2,
+};
+
+/**
* enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
* Disable (flag attribute not present) - Individual TWT
@@ -6291,10 +8444,13 @@ enum qca_wlan_vendor_attr_nan_params {
* STA and AP.
* Broadcast means the session is across multiple STAs and an AP. The
* configuration parameters are announced in Beacon frames by the AP.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE: Required (u8).
* Unsigned 8-bit qca_wlan_vendor_twt_setup_req_type to
- * specify the TWT request type
+ * specify the TWT request type. This is used in TWT SET operation.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
* Enable (flag attribute present) - TWT with trigger support.
@@ -6302,40 +8458,178 @@ enum qca_wlan_vendor_attr_nan_params {
* Trigger means the AP will send the trigger frame to allow STA to send data.
* Without trigger, the STA will wait for the MU EDCA timer before
* transmitting the data.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE: Required (u8)
* 0 - Announced TWT - In this mode, STA may skip few service periods to
* save more power. If STA wants to wake up, it will send a PS-POLL/QoS
* NULL frame to AP.
* 1 - Unannounced TWT - The STA will wakeup during every SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID: Optional (u8)
* Flow ID is the unique identifier for each TWT session.
- * Currently this is not required and dialog ID will be set to zero.
+ * If not provided then dialog ID will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Request and Response
+ * 3. TWT TERMINATE Request and Response
+ * 4. TWT SUSPEND Request and Response
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions for the following
+ * 1. TWT TERMINATE Request and Response
+ * 2. TWT SUSPEND Request and Response
+ * 4. TWT CLEAR STATISTICS request
+ * 5. TWT GET STATISTICS request and response
+ * If an invalid dialog ID is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
* This attribute (exp) is used along with the mantissa to derive the
* wake interval using the following formula:
* pow(2,exp) = wake_intvl_us/wake_intvl_mantis
* Wake interval is the interval between 2 successive SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION: Flag attribute
* Enable (flag attribute present) - Protection required.
* Disable (flag attribute not present) - Protection not required.
* If protection is enabled, then the AP will use protection
* mechanism using RTS/CTS to self to reserve the airtime.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME: Optional (u32)
* This attribute is used as the SP offset which is the offset from
* TSF after which the wake happens. The units are in microseconds. If
* this attribute is not provided, then the value will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
- * This is the duration of the service period. The units are in TU.
+ * This is the duration of the service period. This is specified as
+ * multiples of 256 microseconds. Valid values are 0x1 to 0xFF.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA: Required (u32)
* This attribute is used to configure wake interval mantissa.
* The units are in TU.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS: Required (u8)
+ * This field is applicable for TWT response only.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * and is passed to the userspace. This is used in TWT SET operation.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT TERMINATE Response
+ * 3. TWT SUSPEND Response
+ * 4. TWT RESUME Response
+ * 5. TWT NUDGE Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE: Required (u8)
+ * This field is applicable for TWT response only.
+ * This field contains response type from the TWT responder and is
+ * passed to the userspace. The values for this field are defined in
+ * enum qca_wlan_vendor_twt_setup_resp_type. This is used in TWT SET
+ * response.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF: Required (u64)
+ * This field is applicable for TWT response only.
+ * This field contains absolute TSF value of the wake time received
+ * from the TWT responder and is passed to the userspace.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED: Flag attribute.
+ * Enable (flag attribute present) - Indicates that the TWT responder
+ * supports reception of TWT information frame from the TWT requestor.
+ * Disable (flag attribute not present) - Indicates that the responder
+ * doesn't support reception of TWT information frame from requestor.
+ * This is used in
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT session
+ * is being configured. This is used in AP mode to represent the respective
+ * client.
+ * In AP mode, this is a required parameter in response for
+ * 1. TWT SET
+ * 2. TWT GET
+ * 3. TWT TERMINATE
+ * 4. TWT SUSPEND
+ * In STA mode, this is an optional parameter in request and response for
+ * the above four TWT operations.
+ * In AP mode, this is a required parameter in request for
+ * 1. TWT GET
+ * 2. TWT TERMINATE
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL: Optional (u32)
+ * Minimum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL: Optional (u32)
+ * Maximum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION: Optional (u32)
+ * Minimum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION: Optional (u32)
+ * Maximum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE: Optional (u32)
+ * TWT state for the given dialog id. The values for this are represented
+ * by enum qca_wlan_twt_setup_state.
+ * This is obtained through TWT GET operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA: Optional (u32)
+ * This attribute is used to configure wake interval mantissa.
+ * The unit is microseconds. This attribute, when specified, takes
+ * precedence over QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA.
+ * This parameter is used for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID: Optional (u8)
+ * This attribute is used to configure Broadcast TWT ID.
+ * The Broadcast TWT ID indicates a specific Broadcast TWT for which the
+ * transmitting STA is providing TWT parameters. The allowed values are 0 to 31.
+ * This parameter is used for
+ * 1. TWT SET Request
+ * 2. TWT TERMINATE Request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION: Optional (u8)
+ * This attribute is used to configure Broadcast TWT recommendation.
+ * The Broadcast TWT Recommendation subfield contains a value that indicates
+ * recommendations on the types of frames that are transmitted by TWT
+ * scheduled STAs and scheduling AP during the broadcast TWT SP.
+ * The allowed values are 0 - 3.
+ * This parameter is used for
+ * 1. TWT SET Request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE: Optional (u8)
+ * This attribute is used to configure Broadcast TWT Persistence.
+ * The Broadcast TWT Persistence subfield indicates the number of
+ * TBTTs during which the Broadcast TWT SPs corresponding to this
+ * broadcast TWT Parameter set are present. The number of beacon intervals
+ * during which the Broadcast TWT SPs are present is equal to the value in the
+ * Broadcast TWT Persistence subfield plus 1 except that the value 255
+ * indicates that the Broadcast TWT SPs are present until explicitly terminated.
+ * This parameter is used for
+ * 1. TWT SET Request
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -6350,6 +8644,25 @@ enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+ /* TWT Response only attributes */
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE = 12,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF = 13,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED = 14,
+
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR = 15,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL = 16,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL = 17,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION = 18,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION = 19,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE = 20,
+
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA = 21,
+
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID = 22,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION = 23,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE = 24,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
@@ -6357,24 +8670,114 @@ enum qca_wlan_vendor_attr_twt_setup {
};
/**
- * enum qca_wlan_vendor_attr_twt_resume: Represents attributes for
+ * enum qca_wlan_vendor_twt_status - Represents the status of the requested
+ * TWT operation
+ *
+ * @QCA_WLAN_VENDOR_TWT_STATUS_OK: TWT request successfully completed
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED: TWT not enabled
+ * @QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID: TWT dialog ID is already used
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY: TWT session is busy
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST: TWT session does not exist
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED: TWT session not in suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM: Invalid parameters
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY: FW not ready
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE: FW resource exhausted
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK: Peer AP/STA did not ACK the
+ * request/response frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE: Peer AP did not send the response
+ * frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_DENIED: AP did not accept the request
+ * @QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR: Adding TWT dialog failed due to an
+ * unknown reason
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED: TWT session already in
+ * suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID: FW has dropped the frame due to
+ * invalid IE in the received TWT frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE: Parameters received from
+ * the responder are not in the specified range
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to request from the responder. Used on the TWT_TERMINATE
+ * notification from the firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to roaming. Used on the TWT_TERMINATE notification from the
+ * firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE: FW terminated the
+ * TWT session due to SCC (Single Channel Concurrency) and MCC (Multi Channel
+ * Concurrency). Used on the TWT_TERMINATE notification from the firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS: FW rejected the TWT setup
+ * request due to roaming in progress.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS: FW rejected the TWT
+ * setup request due to channel switch in progress.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS: FW rejected the TWT setup
+ * request due to scan in progress.
+ */
+enum qca_wlan_vendor_twt_status {
+ QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED = 1,
+ QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID = 2,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY = 3,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST = 4,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED = 5,
+ QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM = 6,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY = 7,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE = 8,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK = 9,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE = 10,
+ QCA_WLAN_VENDOR_TWT_STATUS_DENIED = 11,
+ QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR = 12,
+ QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED = 13,
+ QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID = 14,
+ QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE = 15,
+ QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE = 16,
+ QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE = 17,
+ QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE = 18,
+ QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS = 19,
+ QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20,
+ QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_resume - Represents attributes for
* TWT (Target Wake Time) resume request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT: Optional (u8)
- * This attribute is used as the SP offset which is the offset from
- * TSF after which the wake happens. The units are in microseconds.
- * If this attribute is not provided, then the value will be set to
- * zero.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT: Optional (u32)
+ * These attributes are used as the SP offset which is the offset from TSF after
+ * which the wake happens. The units are in microseconds. Please note that
+ * _NEXT_TWT is limited to u8 whereas _NEXT2_TWT takes the u32 data.
+ * _NEXT2_TWT takes the precedence over _NEXT_TWT and thus the recommendation
+ * is to use _NEXT2_TWT. If neither of these attributes is provided, the value
+ * will be set to zero.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE: Required (u32)
* This attribute represents the next TWT subfield size.
+ * Value 0 represents 0 bits, 1 represents 32 bits, 2 for 48 bits,
+ * and 4 for 64 bits.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID: Required (u8).
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session to resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer to which TWT Resume is
+ * being sent. This is used in AP mode to represent the respective
+ * client and is a required parameter. In STA mode, this is an optional
+ * parameter
*/
enum qca_wlan_vendor_attr_twt_resume {
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT = 1,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
@@ -6383,6 +8786,232 @@ enum qca_wlan_vendor_attr_twt_resume {
};
/**
+ * enum qca_wlan_vendor_attr_twt_nudge - Represents attributes for
+ * TWT (Target Wake Time) nudge request. TWT nudge is a combination of suspend
+ * and resume in a single request. These attributes are sent as part of
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID: Required (u8)
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session to suspend and resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in TWT NUDGE request
+ * and response.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME: Required (u32)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE: Required (u32)
+ * This attribute represents the next TWT subfield size.
+ * Value 0 represents 0 bits, 1 represents 32 bits, 2 for 48 bits,
+ * and 4 for 64 bits.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer to which TWT Suspend and Resume is
+ * being sent. This is used in AP mode to represent the respective
+ * client and is a required parameter. In STA mode, this is an optional
+ * parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF: Optional (u64)
+ * This field contains absolute TSF value of the time at which the TWT
+ * session will be resumed.
+ */
+enum qca_wlan_vendor_attr_twt_nudge {
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_stats: Represents attributes for
+ * TWT (Target Wake Time) get statistics and clear statistics request.
+ * These attributes are sent as part of
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID: Required (u8)
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session for get and clear TWT statistics.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which TWT Statistics
+ * is required.
+ * In AP mode this is used to represent the respective
+ * client and is a required parameter for
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request and response
+ * In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period in microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION: Required (u32)
+ * Average of the actual wake duration observed so far. Unit is microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS: Required (u32)
+ * The number of TWT service periods elapsed so far.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION: Required (u32)
+ * This is the minimum value of the wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION: Required (u32)
+ * This is the maximum value of wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU: Required (u32)
+ * Average number of MPDUs transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU: Required (u32)
+ * Average number of MPDUs received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE: Required (u32)
+ * Average number of bytes transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE: Required (u32)
+ * Average number of bytes received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS: Required (u32)
+ * Status of the TWT GET STATISTICS request.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ */
+enum qca_wlan_vendor_attr_twt_stats {
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION = 7,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU = 8,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU = 9,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE = 10,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_twt_get_capa - Represents the bitmap of TWT capabilities
+ * supported by the device and the peer.
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_GET_CAPABILITIES
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUESTOR: TWT requestor support is advertised by
+ * TWT non-scheduling STA. This capability is advertised in the HE
+ * Capability/Extended Capabilities information element in the
+ * Association Request frame by the device.
+ *
+ * @QCA_WLAN_TWT_CAPA_RESPONDER: TWT responder support is advertised by
+ * the TWT scheduling AP. This capability is advertised in the Extended
+ * Capabilities/HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_BROADCAST: On the requestor side, this indicates support
+ * for the broadcast TWT functionality. On the responder side, this indicates
+ * support for the role of broadcast TWT scheduling functionality. This
+ * capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_TWT_FLEXIBLE: The device supports flexible TWT schedule.
+ * This capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUIRED: The TWT Required is advertised by AP to indicate
+ * that it mandates the associated HE STAs to support TWT. This capability is
+ * advertised by AP in the HE Operation Parameters field of the HE Operation
+ * information element.
+ */
+enum qca_wlan_twt_capa {
+ QCA_WLAN_TWT_CAPA_REQUESTOR = BIT(0),
+ QCA_WLAN_TWT_CAPA_RESPONDER = BIT(1),
+ QCA_WLAN_TWT_CAPA_BROADCAST = BIT(2),
+ QCA_WLAN_TWT_CAPA_FLEXIBLE = BIT(3),
+ QCA_WLAN_TWT_CAPA_REQUIRED = BIT(4),
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_capability - Represents attributes for TWT
+ * get capabilities request type. Used by QCA_WLAN_TWT_GET_CAPABILITIES TWT
+ * operation.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT capabilities
+ * are being queried. This is used in AP mode to represent the respective
+ * client. In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF: (u16).
+ * Self TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER: (u16).
+ * Peer TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ */
+enum qca_wlan_vendor_attr_twt_capability {
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_twt_setup_resp_type - Represents the response type by
+ * the TWT responder
+ *
+ * @QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE: TWT responder suggests TWT
+ * parameters that are different from TWT requesting STA suggested
+ * or demanded TWT parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_DICTATE: TWT responder demands TWT
+ * parameters that are different from TWT requesting STA TWT suggested
+ * or demanded parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_REJECT: TWT responder rejects TWT
+ * setup
+ * @QCA_WLAN_VENDOR_TWT_RESP_ACCEPT: TWT responder accepts the TWT
+ * setup.
+ */
+enum qca_wlan_vendor_twt_setup_resp_type {
+ QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE = 1,
+ QCA_WLAN_VENDOR_TWT_RESP_DICTATE = 2,
+ QCA_WLAN_VENDOR_TWT_RESP_REJECT = 3,
+ QCA_WLAN_VENDOR_TWT_RESP_ACCEPT = 4,
+};
+
+/**
* enum qca_wlan_vendor_twt_setup_req_type - Required (u8)
* Represents the setup type being requested for TWT.
* @QCA_WLAN_VENDOR_TWT_SETUP_REQUEST: STA is not specifying all the TWT
@@ -6451,13 +9080,61 @@ enum qca_wlan_vendor_attr_roam_scan {
};
/**
+ * enum qca_wlan_vendor_cfr_data_transport_modes - Defines QCA vendor CFR data
+ * transport modes and is used by the attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE as a part of the vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ * @QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS: Use relayfs to send CFR data.
+ * @QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS: Use netlink events to send CFR
+ * data. The data shall be encapsulated within
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA along with the vendor sub command
+ * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG as an asynchronous event.
+ */
+enum qca_wlan_vendor_cfr_data_transport_modes {
+ QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS = 0,
+ QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS = 1,
+};
+
+/**
* enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by
* attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor
* command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ * @QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL: CFR method using QoS Null frame
+ * @QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE: CFR method using QoS Null frame
+ * with phase
+ * @QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE: CFR method using Probe Response frame
*/
enum qca_wlan_vendor_cfr_method {
- /* CFR method using QOS Null frame */
QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+ QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE = 1,
+ QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_capture_type - QCA vendor CFR capture type used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_FTM: Filter directed FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: Filter all FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: Filter NDPA NDP directed frames.
+ * @QCA_WLAN_VENDOR_CFR_TA_RA: Filter frames based on TA/RA/Subtype which
+ * is provided by one or more of below attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ * @QCA_WLAN_CFR_ALL_PACKET: Filter all packets.
+ * @QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL: Filter all NDPA NDP frames.
+ */
+enum qca_wlan_vendor_cfr_capture_type {
+ QCA_WLAN_VENDOR_CFR_DIRECT_FTM = 0,
+ QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK = 1,
+ QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP = 2,
+ QCA_WLAN_VENDOR_CFR_TA_RA = 3,
+ QCA_WLAN_VENDOR_CFR_ALL_PACKET = 4,
+ QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL = 5,
};
/**
@@ -6465,44 +9142,201 @@ enum qca_wlan_vendor_cfr_method {
* QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
* Channel Frequency Response capture parameters and enable periodic CFR
* capture.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR: Optional (6-byte MAC address)
+ * MAC address of peer. This is for CFR version 1 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE: Required (flag)
+ * Enable peer CFR capture. This attribute is mandatory to enable peer CFR
+ * capture. If this attribute is not present, peer CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH: Optional (u8)
+ * BW of measurement, attribute uses the values in enum nl80211_chan_width
+ * Supported values: 20, 40, 80, 80+80, 160.
+ * Note that all targets may not support all bandwidths.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY: Optional (u32)
+ * Periodicity of CFR measurement in milliseconds.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 milliseconds (default).
+ * 0 for one shot capture.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD: Optional (u8)
+ * Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE: Optional (flag)
+ * Enable periodic CFR capture.
+ * This attribute is mandatory for version 1 to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION: Optional (u8)
+ * Value is 1 or 2 since there are two versions of CFR capture. Two versions
+ * can't be enabled at same time. This attribute is mandatory if target
+ * support both versions and use one of them.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP: Optional (u32)
+ * This attribute is mandatory for version 2 if
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY is used.
+ * Bits 15:0 bitfield indicates which group is to be enabled.
+ * Bits 31:16 Reserved for future use.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION: Optional (u32)
+ * CFR capture duration in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL: Optional (u32)
+ * CFR capture interval in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE: Optional (u32)
+ * CFR capture type is defined in enum qca_wlan_vendor_cfr_capture_type.
+ * This attribute is mandatory for version 2.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK: Optional (u64)
+ * Bitfield indicating which user in the current UL MU transmissions are
+ * enabled for CFR capture. Bits 36 to 0 indicate user indexes for 37 users in
+ * a UL MU transmission. If bit 0 is set, the CFR capture will happen for user
+ * index 0 in the current UL MU transmission. If bits 0 and 2 are set, CFR
+ * capture for UL MU TX corresponds to user indices 0 and 2. Bits 63:37 are
+ * reserved for future use. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT: Optional (u32)
+ * Indicates the number of consecutive RX frames to be skipped before CFR
+ * capture is enabled again. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE: Nested attribute containing
+ * one or more %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY: Nested attribute containing
+ * the following group attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER: Optional (u32)
+ * Target supports multiple groups for some configurations. The group number
+ * can be any value between 0 and 15. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA: Optional (6-byte MAC address)
+ * Transmitter address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA: Optional (6-byte MAC address)
+ * Receiver address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK: Optional (6-byte MAC address)
+ * Mask of transmitter address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK: Optional (6-byte MAC address)
+ * Mask of receiver address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS: Optional (u32)
+ * Indicates frames with a specific NSS will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 7:0 request CFR
+ * capture to be done for frames matching the NSS specified within this bitmask.
+ * Bits 31:8 are reserved for future use. Bits 7:0 map to NSS:
+ * bit 0 : NSS 1
+ * bit 1 : NSS 2
+ * ...
+ * bit 7 : NSS 8
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW: Optional (u32)
+ * Indicates frames with a specific bandwidth will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 4:0 request CFR
+ * capture to be done for frames matching the bandwidths specified within this
+ * bitmask. Bits 31:5 are reserved for future use. Bits 4:0 map to bandwidth
+ * numerated in enum nl80211_band (although not all bands may be supported
+ * by a given device).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER: Optional (u32)
+ * Management frames matching the subtype filter categories will be filtered in
+ * by MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Management frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. For example, Beacon frame control type
+ * is 8 and its value is 1 << 8 = 0x100. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER: Optional (u32)
+ * Control frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Control frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER: Optional (u32)
+ * Data frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Data frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE: Optional (u8)
+ * Userspace can use this attribute to specify the driver about which transport
+ * mode shall be used by the driver to send CFR data to userspace. Uses values
+ * from enum qca_wlan_vendor_cfr_data_transport_modes. When this attribute is
+ * not present, the driver shall use the default transport mechanism which is
+ * QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID: Optional (u32)
+ * Userspace can use this attribute to specify the nl port id of the application
+ * which receives the CFR data and processes it further so that the drivers can
+ * unicast the netlink events to a specific application. Optionally included
+ * when QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE is set to
+ * QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS, not required otherwise. The drivers
+ * shall multicast the netlink events when this attribute is not included.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA: Required (NLA_BINARY).
+ * This attribute will be used by the driver to encapsulate and send CFR data
+ * to userspace along with QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG as an
+ * asynchronous event when the driver is configured to send CFR data using
+ * netlink events with %QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS.
*/
enum qca_wlan_vendor_peer_cfr_capture_attr {
QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
- /* 6-byte MAC address of the peer.
- * This attribute is mandatory.
- */
QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1,
- /* Enable peer CFR Capture, flag attribute.
- * This attribute is mandatory to enable peer CFR capture.
- * If this attribute is not present, peer CFR capture is disabled.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2,
- /* BW of measurement, attribute uses the values in enum nl80211_chan_width
- * Supported values: 20, 40, 80, 80+80, 160.
- * Note that all targets may not support all bandwidths.
- * u8 attribute. This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3,
- /* Periodicity of CFR measurement in msec.
- * Periodicity should be a multiple of Base timer.
- * Current Base timer value supported is 10 msecs (default).
- * 0 for one shot capture. u32 attribute.
- * This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4,
- /* Method used to capture Channel Frequency Response.
- * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
- * u8 attribute. This attribute is mandatory if attribute
- * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
- */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5,
- /* Enable periodic CFR capture, flag attribute.
- * This attribute is mandatory to enable Periodic CFR capture.
- * If this attribute is not present, periodic CFR capture is disabled.
- */
QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION = 7,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP = 8,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE = 11,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK = 12,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE = 14,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY = 15,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER = 16,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA = 17,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA = 18,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK = 19,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK = 20,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS = 21,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW = 22,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER = 23,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER = 24,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER = 25,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE = 26,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID = 27,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA = 28,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
@@ -7131,21 +9965,1168 @@ enum qca_vendor_attr_interop_issues_ap {
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
};
-/*
- * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command
+/**
+ * enum qca_vendor_oem_device_type - Represents the target device in firmware.
+ * It is used by QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_VIRTUAL: The command is intended for
+ * a virtual device.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_PHYSICAL: The command is intended for
+ * a physical device.
+ */
+enum qca_vendor_oem_device_type {
+ QCA_VENDOR_OEM_DEVICE_VIRTUAL = 0,
+ QCA_VENDOR_OEM_DEVICE_PHYSICAL = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
*
- * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
- * command QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this attribute.
- * NLA_BINARY attribute, the max size is 1024 bytes.
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: This NLA_BINARY attribute is
+ * used to set/query the data to/from the firmware. On query, the same
+ * attribute is used to carry the respective data in the reply sent by the
+ * driver to userspace. The request to set/query the data and the format of the
+ * respective data from the firmware are embedded in the attribute. The
+ * maximum size of the attribute payload is 1024 bytes.
+ * Userspace has to set the QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED
+ * attribute when the data is queried from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
+ * based on this field. This optional attribute is included to specify whether
+ * the device type is a virtual device or a physical device for the
+ * command/event. This attribute can be omitted for a virtual device (default)
+ * command/event.
+ * This u8 attribute is used to carry information for the device type using
+ * values defined by enum qca_vendor_oem_device_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED: This NLA_FLAG attribute
+ * is set when the userspace queries data from the firmware. This attribute
+ * should not be set when userspace sets the OEM data to the firmware.
*/
enum qca_wlan_vendor_attr_oem_data_params {
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
+ QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
};
+
+/**
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext - Defines attributes to be
+ * used with vendor command/event QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required
+ * Nested attribute containing multiple ranges with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32)
+ * Starting center frequency in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32)
+ * Ending center frequency in MHz.
+ */
+enum qca_wlan_vendor_attr_avoid_frequency_ext {
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3,
+
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX =
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST - 1
+};
+
+/*
+ * enum qca_wlan_vendor_attr_add_sta_node_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE.
+ */
+enum qca_wlan_vendor_attr_add_sta_node_params {
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_INVALID = 0,
+ /* 6 byte MAC address of STA */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR = 1,
+ /* Authentication algorithm used by the station of size u16;
+ * defined in enum nl80211_auth_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_btc_chain_mode - Specifies BT coex chain mode.
+ * This enum defines the valid set of values of BT coex chain mode.
+ * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
+ * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
+ * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ */
+enum qca_btc_chain_mode {
+ QCA_BTC_CHAIN_SHARED = 0,
+ QCA_BTC_CHAIN_SEPARATED = 1,
+};
+
+/**
+ * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
+ * chain mode.
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE: u32 attribute.
+ * Indicates the BT coex chain mode, are 32-bit values from
+ * enum qca_btc_chain_mode. This attribute is mandatory.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE_RESTART: flag attribute.
+ * If set, vdev should be restarted when BT coex chain mode is updated.
+ * This attribute is optional.
+ */
+enum qca_vendor_attr_btc_chain_mode {
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_INVALID = 0,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE = 1,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART = 2,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX =
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_wlan_sta_flags - Station feature flags
+ * Bits will be set to 1 if the corresponding features are enabled.
+ * @QCA_VENDOR_WLAN_STA_FLAG_AMPDU: AMPDU is enabled for the station
+ * @QCA_VENDOR_WLAN_STA_FLAG_TX_STBC: TX Space-time block coding is enabled
+ for the station
+ * @QCA_VENDOR_WLAN_STA_FLAG_RX_STBC: RX Space-time block coding is enabled
+ for the station
+ */
+enum qca_vendor_wlan_sta_flags {
+ QCA_VENDOR_WLAN_STA_FLAG_AMPDU = BIT(0),
+ QCA_VENDOR_WLAN_STA_FLAG_TX_STBC = BIT(1),
+ QCA_VENDOR_WLAN_STA_FLAG_RX_STBC = BIT(2),
+};
+
+/**
+ * enum qca_vendor_wlan_sta_guard_interval - Station guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_800_NS: Legacy normal guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_400_NS: Legacy short guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_1600_NS: Guard interval used by HE
+ * @QCA_VENDOR_WLAN_STA_GI_3200_NS: Guard interval used by HE
+ */
+enum qca_vendor_wlan_sta_guard_interval {
+ QCA_VENDOR_WLAN_STA_GI_800_NS = 0,
+ QCA_VENDOR_WLAN_STA_GI_400_NS = 1,
+ QCA_VENDOR_WLAN_STA_GI_1600_NS = 2,
+ QCA_VENDOR_WLAN_STA_GI_3200_NS = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC:
+ * Required attribute in request for AP mode only, 6-byte MAC address,
+ * corresponding to the station's MAC address for which information is
+ * requested. For STA mode this is not required as the info always correspond
+ * to the self STA and the current/last association.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS:
+ * Optionally used in response, u32 attribute, contains a bitmap of different
+ * fields defined in enum qca_vendor_wlan_sta_flags, used in AP mode only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL:
+ * Optionally used in response, u32 attribute, possible values are defined in
+ * enum qca_vendor_wlan_sta_guard_interval, used in AP mode only.
+ * Guard interval used by the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Value indicates the number of data frames received from station with retry
+ * bit set to 1 in FC.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Counter for number of data frames with broadcast or multicast address in
+ * the destination address received from the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED:
+ * Optionally used in response, u32 attribute, used in both STA and AP modes.
+ * Value indicates the number of data frames successfully transmitted only
+ * after retrying the packets and for which the TX status has been updated
+ * back to host from target.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED:
+ * Optionally used in response, u32 attribute, used in both STA and AP mode.
+ * Value indicates the number of data frames not transmitted successfully even
+ * after retrying the packets for the number of times equal to the total number
+ * of retries allowed for that packet and for which the TX status has been
+ * updated back to host from target.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Counter in the target for the number of data frames successfully transmitted
+ * to the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Value indicates the number of data frames successfully transmitted only
+ * after retrying the packets.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED:
+ * Optionally used in response, u32 attribute, used in both STA & AP mode.
+ * Value indicates the number of data frames not transmitted successfully even
+ * after retrying the packets for the number of times equal to the total number
+ * of retries allowed for that packet.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT: u32, used in
+ * the STA mode only. Represent the number of probe requests sent by the STA
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. If queried in the disconnected state, this represents the
+ * count for the last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT: u32, used in
+ * the STA mode. Represent the number of probe responses received by the station
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. When queried in the disconnected state, this represents the
+ * count when in last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT: u32, used in the
+ * STA mode only. Represents the total number of frames sent out by STA
+ * including Data, ACK, RTS, CTS, Control Management. This data is maintained
+ * only for the connect session. Represents the count of last connected session,
+ * when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT: u32, used in the STA mode.
+ * Total number of RTS sent out by the STA. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT: u32, used in the
+ * STA mode.Represent the number of RTS transmission failure that reach retry
+ * limit. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT: u32, used in
+ * the STA mode. Represent the total number of non aggregated frames transmitted
+ * by the STA. This data is maintained per connect session. Represents the count
+ * of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT: u32, used in the
+ * STA mode. Represent the total number of aggregated frames transmitted by the
+ * STA. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT: u32, used in
+ * the STA mode. Represents the number of received frames with a good PLCP. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT: u32,
+ * used in the STA mode. Represents the number of occasions that no valid
+ * delimiter is detected by A-MPDU parser. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT: u32, used in the
+ * STA mode. Represents the number of frames for which CRC check failed in the
+ * MAC. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT: u32, used in the
+ * STA mode. Represents the number of unicast ACKs received with good FCS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT: u32, used in the STA
+ * mode. Represents the number of received Block Acks. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT: u32, used in the STA
+ * mode. Represents the number of beacons received from the connected BSS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT: u32, used in the
+ * STA mode. Represents the number of beacons received by the other BSS when in
+ * connected state (through the probes done by the STA). This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT: u64, used in
+ * the STA mode. Represents the number of received DATA frames with good FCS and
+ * matching Receiver Address when in connected state. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT: u32, used in the
+ * STA mode. Represents the number of RX Data multicast frames dropped by the HW
+ * when in the connected state. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS: u32, used in the
+ * STA mode. This represents the target power in dBm for the transmissions done
+ * to the AP in 2.4 GHz at 1 Mbps (DSSS) rate. This data is maintained per
+ * connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 5 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in
+ * the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for for transmissions done
+ * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT: u32, used
+ * in the STA mode. This represents the Nested attribute representing the
+ * overflow counts of each receive buffer allocated to the hardware during the
+ * STA's connection. The number of hw buffers might vary for each WLAN
+ * solution and hence this attribute represents the nested array of all such
+ * HW buffer count. This data is maintained per connect session. Represents
+ * the count of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER: u32, Max TX power (dBm)
+ * allowed as per the regulatory requirements for the current or last connected
+ * session. Used in the STA mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER: u32, Latest TX power
+ * (dBm) used by the station in its latest unicast frame while communicating
+ * to the AP in the connected state. When queried in the disconnected state,
+ * this represents the TX power used by the STA with last AP communication
+ * when in connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL: u32, Adaptive noise immunity
+ * level used to adjust the RX sensitivity. Represents the current ANI level
+ * when queried in the connected state. When queried in the disconnected
+ * state, this corresponds to the latest ANI level at the instance of
+ * disconnection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES: Binary attribute containing
+ * the raw information elements from Beacon frames. Represents the Beacon frames
+ * of the current BSS in the connected state. When queried in the disconnected
+ * state, these IEs correspond to the last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES: Binary attribute
+ * containing the raw information elements from Probe Response frames.
+ * Represents the Probe Response frames of the current BSS in the connected
+ * state. When queried in the disconnected state, these IEs correspond to the
+ * last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON: u32, Driver
+ * disconnect reason for the last disconnection if the disconnection is
+ * triggered from the host driver. The values are referred from
+ * enum qca_disconnect_reason_codes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with an invalid MIC or a missing MME when PMF is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with the packet number less than or equal to the
+ * last received packet number when PMF is enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT: u32, used in STA
+ * mode only. This represents the number of Beacon frames received from this
+ * station with an invalid MIC or a missing MME when beacon protection is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents number of Beacon frames received from this station with
+ * the packet number less than or equal to the last received packet number when
+ * beacon protection is enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE: u32, used in
+ * STA mode only. The driver uses this attribute to populate the connection
+ * failure reason codes and the values are defined in
+ * enum qca_sta_connect_fail_reason_codes. Userspace applications can send
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command after receiving
+ * a connection failure indication from the driver. The driver shall not
+ * include this attribute in response to the
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO command if there is no connection
+ * failure observed in the last attempted connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE: u32, latest TX rate (Kbps)
+ * used by the station in its last TX frame while communicating to the AP in the
+ * connected state. When queried in the disconnected state, this represents the
+ * rate used by the STA in the last TX frame to the AP when it was connected.
+ * This attribute is used for STA mode only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX: u32, used in STA mode only.
+ * This represents the rate index used by the STA for the last TX frame to the
+ * AP. When queried in the disconnected state, this gives the last RIX used by
+ * the STA in the last TX frame to the AP when it was connected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT: u32, used in STA
+ * mode only. This represents the number of times the STA TSF goes out of sync
+ * from the AP after the connection. If queried in the disconnected state, this
+ * gives the count of TSF out of sync for the last connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON: u32, used in STA
+ * mode only. This represents the roam trigger reason for the last roaming
+ * attempted by the firmware. This can be queried either in connected state or
+ * disconnected state. Each bit of this attribute represents the different
+ * roam trigger reason code which are defined in enum qca_vendor_roam_triggers.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON: u32, used in STA mode
+ * only. This represents the roam fail reason for the last failed roaming
+ * attempt by the firmware. Different roam failure reason codes are specified
+ * in enum qca_vendor_roam_fail_reasons. This can be queried either in
+ * connected state or disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON: u32, used in
+ * STA mode only. This represents the roam invoke fail reason for the last
+ * failed roam invoke. Different roam invoke failure reason codes
+ * are specified in enum qca_vendor_roam_invoke_fail_reasons. This can be
+ * queried either in connected state or disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY: u32, used in STA mode only.
+ * This represents the average congestion duration of uplink frames in MAC
+ * queue in unit of ms. This can be queried either in connected state or
+ * disconnected state.
+ */
+enum qca_wlan_vendor_attr_get_sta_info {
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC = 1,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS = 2,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL = 3,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED = 6,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED = 7,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL = 8,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY = 9,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED = 10,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT = 11,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT = 12,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT = 14,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT = 15,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT = 16,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT = 17,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT = 18,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT = 19,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT = 20,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT = 21,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT = 22,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT = 23,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT = 24,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT = 25,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT = 26,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS = 27,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS = 28,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0 = 29,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS = 30,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0 = 31,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT = 32,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER = 33,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER = 34,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL = 35,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT = 39,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT = 40,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT = 41,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT = 42,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE = 43,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE = 44,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX = 45,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT = 46,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON = 47,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY = 50,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_update_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS: Type is NLA_UNSPEC.
+ * Used in STA mode. This attribute represents the list of channel center
+ * frequencies in MHz (u32) the station has learnt during the last connection
+ * or roaming attempt. This information shall not signify the channels for
+ * an explicit scan request from the user space. Host drivers can update this
+ * information to the user space in both connected and disconnected state.
+ * In the disconnected state this information shall signify the channels
+ * scanned in the last connection/roam attempt that lead to the disconnection.
+ */
+enum qca_wlan_vendor_attr_update_sta_info {
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_disconnect_reason_codes - Specifies driver disconnect reason codes.
+ * Used when the driver triggers the STA to disconnect from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSPECIFIED: The host driver triggered the
+ * disconnection with the AP due to unspecified reasons.
+ *
+ * @QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE: The host driver triggered the
+ * disconnection with the AP due to a roaming failure. This roaming is triggered
+ * internally (host driver/firmware).
+ *
+ * @QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE: The driver disconnected from
+ * the AP when the user/external triggered roaming fails.
+ *
+ * @QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE: This reason code is used
+ * by the host driver whenever gateway reachability failure is detected and the
+ * driver disconnects with AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA: The driver disconnected from
+ * the AP on a channel switch announcement from it with an unsupported channel.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR: On a concurrent AP start
+ * with indoor channels disabled and if the STA is connected on one of these
+ * disabled channels, the host driver disconnected the STA with this reason
+ * code.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED: Disconnection due to an
+ * explicit request from the user to disable the current operating channel.
+ *
+ * @QCA_DISCONNECT_REASON_DEVICE_RECOVERY: STA disconnected from the AP due to
+ * the internal host driver/firmware recovery.
+ *
+ * @QCA_DISCONNECT_REASON_KEY_TIMEOUT: The driver triggered the disconnection on
+ * a timeout for the key installations from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE: The dDriver disconnected the
+ * STA on a band change request from the user space to a different band from the
+ * current operation channel/band.
+ *
+ * @QCA_DISCONNECT_REASON_IFACE_DOWN: The STA disconnected from the AP on an
+ * interface down trigger from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL: The host driver disconnected the
+ * STA on getting continuous transmission failures for multiple Data frames.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_INACTIVITY: The STA does a keep alive
+ * notification to the AP by transmitting NULL/G-ARP frames. This disconnection
+ * represents inactivity from AP on such transmissions.
+
+ * @QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT: This reason code is used on
+ * disconnection when SA Query times out (AP does not respond to SA Query).
+ *
+ * @QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE: The host driver disconnected the
+ * STA on missing the beacons continuously from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE: Disconnection due to STA not
+ * able to move to the channel mentioned by the AP in CSA.
+ *
+ * @QCA_DISCONNECT_REASON_USER_TRIGGERED: User triggered disconnection.
+ */
+enum qca_disconnect_reason_codes {
+ QCA_DISCONNECT_REASON_UNSPECIFIED = 0,
+ QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE = 1,
+ QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE = 2,
+ QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE = 3,
+ QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA = 4,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR = 5,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED = 6,
+ QCA_DISCONNECT_REASON_DEVICE_RECOVERY = 7,
+ QCA_DISCONNECT_REASON_KEY_TIMEOUT = 8,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE = 9,
+ QCA_DISCONNECT_REASON_IFACE_DOWN = 10,
+ QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL = 11,
+ QCA_DISCONNECT_REASON_PEER_INACTIVITY = 12,
+ QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT = 13,
+ QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE = 14,
+ QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE = 15,
+ QCA_DISCONNECT_REASON_USER_TRIGGERED = 16,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_driver_disconnect_reason - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE: u32 attribute.
+ * This attribute represents the driver specific reason codes (local
+ * driver/firmware initiated reasons for disconnection) defined
+ * in enum qca_disconnect_reason_codes.
+ */
+enum qca_wlan_vendor_attr_driver_disconnect_reason {
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_MAX =
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_tspec_operation - Operation of the config TSPEC request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION.
+ */
+enum qca_wlan_tspec_operation {
+ QCA_WLAN_TSPEC_ADD = 0,
+ QCA_WLAN_TSPEC_DEL = 1,
+ QCA_WLAN_TSPEC_GET = 2,
+};
+
+/**
+ * enum qca_wlan_tspec_direction - Direction in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-139.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION.
+ */
+enum qca_wlan_tspec_direction {
+ QCA_WLAN_TSPEC_DIRECTION_UPLINK = 0,
+ QCA_WLAN_TSPEC_DIRECTION_DOWNLINK = 1,
+ QCA_WLAN_TSPEC_DIRECTION_DIRECT = 2,
+ QCA_WLAN_TSPEC_DIRECTION_BOTH = 3,
+};
+
+/**
+ * enum qca_wlan_tspec_ack_policy - MAC acknowledgement policy in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-141.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY.
+ */
+enum qca_wlan_tspec_ack_policy {
+ QCA_WLAN_TSPEC_NORMAL_ACK = 0,
+ QCA_WLAN_TSPEC_NO_ACK = 1,
+ /* Reserved */
+ QCA_WLAN_TSPEC_BLOCK_ACK = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_tspec - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION:
+ * u8 attribute. Specify the TSPEC operation of this request. Possible values
+ * are defined in enum qca_wlan_tspec_operation.
+ * Mandatory attribute for all kinds of config TSPEC requests.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID:
+ * u8 attribute. TS ID. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD, QCA_WLAN_TSPEC_DEL,
+ * QCA_WLAN_TSPEC_GET. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION:
+ * u8 attribute. Direction of data carried by the TS. Possible values are
+ * defined in enum qca_wlan_tspec_direction.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD:
+ * Flag attribute. Indicate whether APSD is enabled for the traffic associated
+ * with the TS. set - enabled, not set - disabled.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY:
+ * u8 attribute. User priority to be used for the transport of MSDUs/A-MSDUs
+ * belonging to this TS. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY:
+ * u8 attribute. Indicate whether MAC acknowledgements are required for
+ * MPDUs/A-MSDUs belonging to this TS and the form of those acknowledgements.
+ * Possible values are defined in enum qca_wlan_tspec_ack_policy.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE:
+ * u16 attribute. Specify the nominal size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE:
+ * u16 attribute. Specify the maximum size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL:
+ * u32 attribute. Specify the maximum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MPDU belonging to the TS before this TS
+ * is deleted by the MAC entity at the HC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MSDU belonging to the TS before the
+ * generation of successive QoS(+)CF-Poll is stopped for this TS. A value of
+ * 0xFFFFFFFF disables the suspension interval. The value of the suspension
+ * interval is always less than or equal to the inactivity interval.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE:
+ * u32 attribute. Indicate the lowest data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE:
+ * u32 attribute. Indicate the average data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE:
+ * u32 attribute. Indicate the maximum allowable data rate in bps specified at
+ * the MAC SAP for transport of MSDUs or A-MSDUs belonging to this TS within
+ * the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE:
+ * u32 attribute. Specify the maximum burst size in bytes of the MSDUs/A-MSDUs
+ * belonging to this TS that arrive at the MAC SAP at the peak data rate. A
+ * value of 0 indicates that there are no bursts.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE:
+ * u32 attribute. Indicate the minimum PHY rate in bps for transport of
+ * MSDUs/A-MSDUs belonging to this TS within the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE:
+ * u16 attribute. Specify the excess allocation of time (and bandwidth) over
+ * and above the stated application rates required to transport an MSDU/A-MSDU
+ * belonging to the TS in this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ */
+enum qca_wlan_vendor_attr_config_tspec {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION = 3,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD = 4,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY = 5,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY = 6,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE = 7,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE = 8,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL = 9,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL = 12,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE = 13,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE = 14,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE = 15,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE = 16,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE = 17,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE = 18,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_oci_override_frame_type - OCI override frame type
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ: SA Query Request frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP: SA Query Response frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ: FT Reassociation Request
+ * frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ: FILS Reassociation
+ * Request frame.
+ */
+enum qca_wlan_vendor_oci_override_frame_type {
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ = 1,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP = 2,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ = 3,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oci_override: Represents attributes for
+ * OCI override request. These attributes are used inside nested attribute
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE in QCA vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE: Required attribute, u8.
+ * Values from enum qca_wlan_vendor_oci_override_frame_type used in this
+ * attribute to specify the frame type in which the OCI is to be overridden.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY: Required (u32)
+ * OCI frequency (in MHz) to override in the specified frame type.
+ */
+enum qca_wlan_vendor_attr_oci_override {
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_medium_assess_type - Type of medium assess request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE.
+ */
+enum qca_wlan_medium_assess_type {
+ QCA_WLAN_MEDIUM_ASSESS_CCA = 0,
+ QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_medium_assess - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE:
+ * u8 attribute. Mandatory in all kinds of medium assess requests/responses.
+ * Specify the type of medium assess request and indicate its type in response.
+ * Possible values are defined in enum qca_wlan_medium_assess_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD:
+ * u32 attribute. Mandatory in CCA request.
+ * Specify the assessment period in terms of seconds. Assessment result will be
+ * sent as the response to the CCA request after the assessment period.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Total timer tick count of the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of idle time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Intra BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Overlapping BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Maximum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Minimum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE:
+ * u8 attribute. Mandatory in congestion report request.
+ * 1-enable 0-disable.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD:
+ * u8 attribute. Mandatory in congestion report enable request and will be
+ * ignored if present in congestion report disable request. Possible values are
+ * 0-100. A vendor event QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS with the type
+ * QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT will be sent to userspace if
+ * congestion percentage reaches the configured threshold.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL:
+ * u8 attribute. Optional in congestion report enable request and will be
+ * ignored if present in congestion report disable request.
+ * Specify the interval of congestion report event in terms of seconds. Possible
+ * values are 1-255. Default value 1 will be used if this attribute is omitted
+ * or using invalid values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE:
+ * u8 attribute. Mandatory in congestion report event.
+ * Indicate the actual congestion percentage. Possible values are 0-100.
+ */
+enum qca_wlan_vendor_attr_medium_assess {
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE = 1,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT = 3,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT = 6,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI = 7,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI = 8,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE = 9,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD = 10,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mbssid_tx_vdev_status - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL:
+ * u8 attribute. Notify the TX VDEV status. Possible values 0, 1
+ * belonging to MBSSID/EMA_AP configuration. 0 means Non-Tx VDEV,
+ * 1 means Tx VDEV. Mandatory attribute for all MBSSID VDEV status events.
+ */
+enum qca_wlan_vendor_attr_mbssid_tx_vdev_status {
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_concurrent_sta_policy_config - Concurrent STA policies
+ *
+ * @QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY: Preference to the primary
+ * STA interface has to be given while selecting the connection policies
+ * (e.g., BSSID, band, TX/RX chains, etc.) for the subsequent STA interface.
+ * An interface is set as primary through the attribute
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY. This policy is not
+ * applicable if the primary interface has not been set earlier.
+ *
+ * The intention is not to downgrade the primary STA performance, such as:
+ * - Do not reduce the number of TX/RX chains of primary connection.
+ * - Do not optimize DBS vs. MCC/SCC, if DBS ends up reducing the number of
+ * chains.
+ * - If using MCC, should set the MCC duty cycle of the primary connection to
+ * be higher than the secondary connection.
+ *
+ * @QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED: The connection policies for the
+ * subsequent STA connection shall be chosen to balance with the existing
+ * concurrent STA's performance.
+ * Such as
+ * - Can choose MCC or DBS mode depending on the MCC efficiency and hardware
+ * capability.
+ * - If using MCC, set the MCC duty cycle of the primary connection to be equal
+ * to the secondary.
+ * - Prefer BSSID candidates which will help provide the best "overall"
+ * performance for all the STA connections.
+ */
+enum qca_wlan_concurrent_sta_policy_config {
+ QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY = 0,
+ QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_concurrent_sta_policy - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG:
+ * u8 attribute. Configures the concurrent STA policy configuration.
+ * Possible values are defined in enum qca_wlan_concurrent_sta_policy_config.
+ */
+enum qca_wlan_vendor_attr_concurrent_sta_policy {
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST - 1,
+
+};
+
+/**
+ * enum qca_sta_connect_fail_reason_codes - Defines values carried
+ * by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor
+ * attribute.
+ * @QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received
+ * for unicast Probe Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for
+ * auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not
+ * received from AP.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response
+ * frame is not received from AP.
+ */
+enum qca_sta_connect_fail_reason_codes {
+ QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7,
+};
+
+/**
+ * enum qca_wlan_vendor_usable_channels_filter - Bitmask of different
+ * filters defined in this enum are used in attribute
+ * %QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK.
+ *
+ * @QCA_WLAN_VENDOR_FILTER_CELLULAR_COEX: When this bit is set, the driver
+ * shall filter the channels which are not usable because of coexistence with
+ * cellular radio.
+ * @QCA_WLAN_VENDOR_FILTER_WLAN_CONCURRENCY: When this bit is set, the driver
+ * shall filter the channels which are not usable because of existing active
+ * interfaces in the driver and will result in Multi Channel Concurrency, etc.
+ *
+ */
+enum qca_wlan_vendor_usable_channels_filter {
+ QCA_WLAN_VENDOR_FILTER_CELLULAR_COEX = 0,
+ QCA_WLAN_VENDOR_FILTER_WLAN_CONCURRENCY = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_chan_info - Attributes used inside
+ * %QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_CHAN_INFO nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_INFO_PRIMARY_FREQ:
+ * u32 attribute, required. Indicates the center frequency of the primary
+ * channel in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG0_FREQ:
+ * u32 attribute. Indicates the center frequency of the primary segment of the
+ * channel in MHz. This attribute is required when reporting 40 MHz, 80 MHz,
+ * 160 MHz, and 320 MHz channels.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG1_FREQ:
+ * u32 attribute. Indicates the center frequency of the secondary segment of
+ * 80+80 channel in MHz. This attribute is required only when
+ * QCA_WLAN_VENDOR_ATTR_CHAN_INFO_BANDWIDTH is set to NL80211_CHAN_WIDTH_80P80.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_INFO_BANDWIDTH:
+ * u32 attribute, required. Indicates the bandwidth of the channel, possible
+ * values are defined in enum nl80211_chan_width.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_INFO_IFACE_MODE_MASK:
+ * u32 attribute, required. Indicates all the interface types for which this
+ * channel is usable. This attribute encapsulates bitmasks of interface types
+ * defined in enum nl80211_iftype.
+ *
+ */
+enum qca_wlan_vendor_attr_chan_info {
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_PRIMARY_FREQ = 1,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG0_FREQ = 2,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG1_FREQ = 3,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_BANDWIDTH = 4,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_IFACE_MODE_MASK = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_CHAN_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_usable_channels - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK:
+ * u32 attribute. Indicates the bands from which the channels should be reported
+ * in response. This attribute encapsulates bit masks of bands defined in enum
+ * nl80211_band. Optional attribute, if not present in the request the driver
+ * shall return channels from all supported bands.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK:
+ * u32 attribute. Indicates all the interface types for which the usable
+ * channels information is requested. This attribute encapsulates bitmasks of
+ * interface types defined in enum nl80211_iftype. Optional attribute, if not
+ * present in the request the driver shall send information of all supported
+ * interface modes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK:
+ * u32 attribute. This attribute carries information of all filters that shall
+ * be applied while populating usable channels information by the driver. This
+ * attribute carries bit masks of different filters defined in enum
+ * qca_wlan_vendor_usable_channels_filter. Optional attribute, if not present
+ * in the request the driver shall send information of channels without applying
+ * any of the filters that can be configured through this attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_CHAN_INFO:
+ * Nested attribute. This attribute shall be used by the driver to send
+ * usability information of each channel. The attributes defined in enum
+ * qca_wlan_vendor_attr_chan_info are used inside this attribute.
+ */
+enum qca_wlan_vendor_attr_usable_channels {
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK = 1,
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK = 2,
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK = 3,
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_CHAN_INFO = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_MAX =
+ QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_radar_history: Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY to get DFS radar history.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES: Nested attribute to carry
+ * the list of radar history entries.
+ * Each entry contains freq, timestamp, and radar signal detect flag.
+ * The driver shall add an entry when CAC has finished, or radar signal
+ * has been detected post AP beaconing. The driver shall maintain at least
+ * 8 entries in order to save CAC result for a 160 MHz channel.
+ * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ: u32 attribute.
+ * Channel frequency in MHz.
+ * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP: u64 nanoseconds.
+ * CLOCK_BOOTTIME timestamp when this entry is updated due to CAC
+ * or radar detection.
+ * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED: NLA_FLAG attribute.
+ * This flag indicates radar signal has been detected.
+ */
+enum qca_wlan_vendor_attr_radar_history {
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES = 1,
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ = 2,
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP = 3,
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST,
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_MAX =
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/contrib/wpa/src/common/sae.c b/contrib/wpa/src/common/sae.c
index 08fdbfd18173..74920a78e46a 100644
--- a/contrib/wpa/src/common/sae.c
+++ b/contrib/wpa/src/common/sae.c
@@ -12,6 +12,8 @@
#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/random.h"
#include "crypto/dh_groups.h"
#include "ieee802_11_defs.h"
@@ -107,6 +109,8 @@ void sae_clear_temp_data(struct sae_data *sae)
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
+ wpabuf_free(tmp->own_rejected_groups);
+ wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
@@ -119,6 +123,7 @@ void sae_clear_data(struct sae_data *sae)
return;
sae_clear_temp_data(sae);
crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
os_memset(sae, 0, sizeof(*sae));
}
@@ -164,7 +169,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
* being smaller than prime. */
in_range = const_time_fill_msb((unsigned int) cmp_prime);
/* The algorithm description would skip the next steps if
- * cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
+ * cmp_prime >= 0 (return 0 here), but go through them regardless to
* minimize externally observable differences in behavior. */
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
@@ -275,13 +280,12 @@ fail:
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len, const char *identifier)
+ size_t password_len)
{
u8 counter, k;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[3];
- size_t len[3];
- size_t num_elem;
+ const u8 *addr[2];
+ size_t len[2];
u8 *dummy_password, *tmp_password;
int pwd_seed_odd = 0;
u8 prime[SAE_MAX_ECC_PRIME_LEN];
@@ -319,13 +323,10 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
- if (identifier)
- wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
- identifier);
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
- * base = password [|| identifier]
+ * base = password
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* base || counter)
*/
@@ -333,15 +334,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
addr[0] = tmp_password;
len[0] = password_len;
- num_elem = 1;
- if (identifier) {
- addr[num_elem] = (const u8 *) identifier;
- len[num_elem] = os_strlen(identifier);
- num_elem++;
- }
- addr[num_elem] = &counter;
- len[num_elem] = sizeof(counter);
- num_elem++;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
/*
* Continue for at least k iterations to protect against side-channel
@@ -362,7 +356,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
const_time_select_bin(found, dummy_password, password,
password_len, tmp_password);
- if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
addr, len, pwd_seed) < 0)
break;
@@ -433,13 +427,12 @@ fail:
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len, const char *identifier)
+ size_t password_len)
{
u8 counter, k, sel_counter = 0;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[3];
- size_t len[3];
- size_t num_elem;
+ const u8 *addr[2];
+ size_t len[2];
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
* mask */
u8 mask;
@@ -463,21 +456,14 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
- * password [|| identifier] || counter)
+ * password || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
addr[0] = password;
len[0] = password_len;
- num_elem = 1;
- if (identifier) {
- addr[num_elem] = (const u8 *) identifier;
- len[num_elem] = os_strlen(identifier);
- num_elem++;
- }
- addr[num_elem] = &counter;
- len[num_elem] = sizeof(counter);
- num_elem++;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
k = dragonfly_min_pwe_loop_iter(sae->group);
@@ -492,7 +478,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
}
wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
- if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
addr, len, pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
@@ -525,6 +511,759 @@ fail:
}
+static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
+ size_t num_elem, const u8 *addr[], const size_t len[],
+ u8 *prk)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
+ const char *info, u8 *okm, size_t okm_len)
+{
+ size_t info_len = os_strlen(info);
+
+ if (hash_len == 32)
+ return hmac_sha256_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sswu_curve_param(int group, int *z)
+{
+ switch (group) {
+ case 19:
+ *z = -10;
+ return 0;
+ case 20:
+ *z = -12;
+ return 0;
+ case 21:
+ *z = -4;
+ return 0;
+ case 25:
+ case 29:
+ *z = -5;
+ return 0;
+ case 26:
+ *z = 31;
+ return 0;
+ case 28:
+ *z = -2;
+ return 0;
+ case 30:
+ *z = 7;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
+ size_t prime_len)
+{
+ u8 *bin;
+
+ bin = os_malloc(prime_len);
+ if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
+ wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
+ else
+ wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
+ bin_clear_free(bin, prime_len);
+}
+
+
+static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
+ const struct crypto_bignum *u)
+{
+ int z_int;
+ const struct crypto_bignum *a, *b, *prime;
+ struct crypto_bignum *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
+ *x1a, *x1b, *y = NULL;
+ struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
+ unsigned int m_is_zero, is_qr, is_eq;
+ size_t prime_len;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin1[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin2[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_ec_point *p = NULL;
+
+ if (sswu_curve_param(group, &z_int) < 0)
+ return NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ a = crypto_ec_get_a(ec);
+ b = crypto_ec_get_b(ec);
+
+ u2 = crypto_bignum_init();
+ t1 = crypto_bignum_init();
+ t2 = crypto_bignum_init();
+ z = crypto_bignum_init_uint(abs(z_int));
+ t = crypto_bignum_init();
+ zero = crypto_bignum_init_uint(0);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ three = crypto_bignum_init_uint(3);
+ x1a = crypto_bignum_init();
+ x1b = crypto_bignum_init();
+ x2 = crypto_bignum_init();
+ gx1 = crypto_bignum_init();
+ gx2 = crypto_bignum_init();
+ if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
+ !x1a || !x1b || !x2 || !gx1 || !gx2)
+ goto fail;
+
+ if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
+ goto fail;
+
+ /* m = z^2 * u^4 + z * u^2 */
+ /* --> tmp = z * u^2, m = tmp^2 + tmp */
+
+ /* u2 = u^2
+ * t1 = z * u2
+ * t2 = t1^2
+ * m = t1 = t1 + t2 */
+ if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
+ crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: m", t1, prime_len);
+
+ /* l = CEQ(m, 0)
+ * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
+ * x^(p-2) modulo p which will handle m == 0 case correctly */
+ /* TODO: Make sure crypto_bignum_is_zero() is constant time */
+ m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
+ /* t = m^(p-2) modulo p */
+ if (crypto_bignum_sub(prime, two, t2) < 0 ||
+ crypto_bignum_exptmod(t1, t2, prime, t) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: t", t, prime_len);
+
+ /* b / (z * a) */
+ if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
+ crypto_bignum_inverse(t1, prime, t1) < 0 ||
+ crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
+
+ /* (-b/a) * (1 + t) */
+ if (crypto_bignum_sub(prime, b, t1) < 0 ||
+ crypto_bignum_inverse(a, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(one, t, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
+
+ /* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
+ if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
+ x1 = crypto_bignum_init_set(bin, prime_len);
+ if (!x1)
+ goto fail;
+ debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
+
+ /* gx1 = x1^3 + a * x1 + b */
+ if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
+
+ /* x2 = z * u^2 * x1 */
+ if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
+
+ /* gx2 = x2^3 + a * x2 + b */
+ if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
+
+ /* l = gx1 is a quadratic residue modulo p
+ * --> gx1^((p-1)/2) modulo p is zero or one */
+ if (crypto_bignum_sub(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 1, t1) < 0 ||
+ crypto_bignum_exptmod(gx1, t1, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
+ is_qr = const_time_eq(crypto_bignum_is_zero(t1) |
+ crypto_bignum_is_one(t1), 1);
+
+ /* v = CSEL(l, gx1, gx2) */
+ if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
+ v = crypto_bignum_init_set(bin, prime_len);
+ if (!v)
+ goto fail;
+ debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
+
+ /* x = CSEL(l, x1, x2) */
+ if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
+
+ /* y = sqrt(v)
+ * For prime p such that p = 3 mod 4 --> v^((p+1)/4) */
+ if (crypto_bignum_to_bin(prime, bin1, sizeof(bin1), prime_len) < 0)
+ goto fail;
+ if ((bin1[prime_len - 1] & 0x03) != 3) {
+ wpa_printf(MSG_DEBUG, "SSWU: prime does not have p = 3 mod 4");
+ goto fail;
+ }
+ y = crypto_bignum_init();
+ if (!y ||
+ crypto_bignum_add(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 2, t1) < 0 ||
+ crypto_bignum_exptmod(v, t1, prime, y) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
+
+ /* l = CEQ(LSB(u), LSB(y)) */
+ if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
+ bin2[prime_len - 1] & 0x01);
+
+ /* P = CSEL(l, (x,y), (x, p-y)) */
+ if (crypto_bignum_sub(prime, y, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: p - y", t1, prime_len);
+ if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
+
+ /* output P */
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
+ p = crypto_ec_point_from_bin(ec, x_y);
+
+fail:
+ crypto_bignum_deinit(u2, 1);
+ crypto_bignum_deinit(t1, 1);
+ crypto_bignum_deinit(t2, 1);
+ crypto_bignum_deinit(z, 0);
+ crypto_bignum_deinit(t, 1);
+ crypto_bignum_deinit(x1a, 1);
+ crypto_bignum_deinit(x1b, 1);
+ crypto_bignum_deinit(x1, 1);
+ crypto_bignum_deinit(x2, 1);
+ crypto_bignum_deinit(gx1, 1);
+ crypto_bignum_deinit(gx2, 1);
+ crypto_bignum_deinit(y, 1);
+ crypto_bignum_deinit(v, 1);
+ crypto_bignum_deinit(zero, 0);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(three, 0);
+ forced_memzero(bin, sizeof(bin));
+ forced_memzero(bin1, sizeof(bin1));
+ forced_memzero(bin2, sizeof(bin2));
+ forced_memzero(x_y, sizeof(x_y));
+ return p;
+}
+
+
+static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier, u8 *pwd_seed)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+
+ /* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
+ addr[0] = password;
+ len[0] = password_len;
+ num_elem = 1;
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
+ pwd_seed) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
+ return 0;
+}
+
+
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 256 / 8)
+ return 32;
+ if (prime_len <= 384 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_ec_point *
+sae_derive_pt_ecc(struct crypto_ec *ec, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t pwd_value_len, hash_len, prime_len;
+ const struct crypto_bignum *prime;
+ struct crypto_bignum *bn = NULL;
+ struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ if (prime_len > SAE_MAX_ECC_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
+ 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
+ pwd_value, pwd_value_len);
+
+ /* u1 = pwd-value modulo p */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
+
+ /* P1 = SSWU(u1) */
+ p1 = sswu(ec, group, bn);
+ if (!p1)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u2 P2", pwd_value,
+ pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
+ pwd_value, pwd_value_len);
+
+ /* u2 = pwd-value modulo p */
+ crypto_bignum_deinit(bn, 1);
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
+
+ /* P2 = SSWU(u2) */
+ p2 = sswu(ec, group, bn);
+ if (!p2)
+ goto fail;
+
+ /* PT = elem-op(P1, P2) */
+ pt = crypto_ec_point_init(ec);
+ if (!pt)
+ goto fail;
+ if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
+ crypto_ec_point_deinit(pt, 1);
+ pt = NULL;
+ }
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_ec_point_deinit(p1, 1);
+ crypto_ec_point_deinit(p2, 1);
+ return pt;
+}
+
+
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 2048 / 8)
+ return 32;
+ if (prime_len <= 3072 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_bignum *
+sae_derive_pt_ffc(const struct dh_group *dh, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ size_t hash_len, prime_len, pwd_value_len;
+ struct crypto_bignum *prime, *order;
+ struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
+ *pt = NULL;
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
+
+ prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
+ order = crypto_bignum_init_set(dh->order, dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = dh->prime_len;
+ if (prime_len > SAE_MAX_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+ if (pwd_value_len > sizeof(pwd_value))
+ goto fail;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element", pwd_value, pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, pwd_value_len);
+
+ /* pwd-value = (pwd-value modulo (p-2)) + 2 */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ tmp = crypto_bignum_init();
+ if (!bn || !one || !two || !tmp ||
+ crypto_bignum_sub(prime, two, tmp) < 0 ||
+ crypto_bignum_mod(bn, tmp, bn) < 0 ||
+ crypto_bignum_add(bn, two, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
+ pwd_value, prime_len);
+
+ /* PT = pwd-value^((p-1)/q) modulo p */
+ pt = crypto_bignum_init();
+ if (!pt ||
+ crypto_bignum_sub(prime, one, tmp) < 0 ||
+ crypto_bignum_div(tmp, order, tmp) < 0 ||
+ crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
+ crypto_bignum_deinit(pt, 1);
+ pt = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PT", pt, prime_len);
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pt;
+}
+
+
+static struct sae_pt *
+sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+
+ if (ssid_len > 32)
+ return NULL;
+
+ pt = os_zalloc(sizeof(*pt));
+ if (!pt)
+ return NULL;
+
+#ifdef CONFIG_SAE_PK
+ os_memcpy(pt->ssid, ssid, ssid_len);
+ pt->ssid_len = ssid_len;
+#endif /* CONFIG_SAE_PK */
+ pt->group = group;
+ pt->ec = crypto_ec_init(group);
+ if (pt->ec) {
+ pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
+ password, password_len,
+ identifier);
+ if (!pt->ecc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+ }
+
+ pt->dh = dh_groups_get(group);
+ if (!pt->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
+ goto fail;
+ }
+
+ pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
+ password, password_len, identifier);
+ if (!pt->ffc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+fail:
+ sae_deinit_pt(pt);
+ return NULL;
+}
+
+
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt = NULL, *last = NULL, *tmp;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
+ tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
+ password_len, identifier);
+ if (!tmp)
+ continue;
+
+ if (last)
+ last->next = tmp;
+ else
+ pt = tmp;
+ last = tmp;
+ }
+
+ return pt;
+}
+
+
+static void sae_max_min_addr(const u8 *addr[], size_t len[],
+ const u8 *addr1, const u8 *addr2)
+{
+ len[0] = ETH_ALEN;
+ len[1] = ETH_ALEN;
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ addr[0] = addr1;
+ addr[1] = addr2;
+ } else {
+ addr[0] = addr2;
+ addr[1] = addr1;
+ }
+}
+
+
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_ec_point *pwe = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime_len = crypto_ec_prime_len(pt->ec);
+ if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
+ bin, bin + prime_len) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ order = crypto_ec_get_order(pt->ec);
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_ec_point_init(pt->ec);
+ if (!pwe ||
+ crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
+ crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
+ crypto_ec_point_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ return pwe;
+}
+
+
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
+ order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = pt->dh->prime_len;
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_bignum_init();
+ if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
+ crypto_bignum_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PWE", pwe, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pwe;
+}
+
+
+void sae_deinit_pt(struct sae_pt *pt)
+{
+ struct sae_pt *prev;
+
+ while (pt) {
+ crypto_ec_point_deinit(pt->ecc_pt, 1);
+ crypto_bignum_deinit(pt->ffc_pt, 1);
+ crypto_ec_deinit(pt->ec);
+ prev = pt;
+ pt = pt->next;
+ os_free(prev);
+ }
+}
+
+
static int sae_derive_commit_element_ecc(struct sae_data *sae,
struct crypto_bignum *mask)
{
@@ -596,18 +1335,78 @@ static int sae_derive_commit(struct sae_data *sae)
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- const char *identifier, struct sae_data *sae)
+ struct sae_data *sae)
{
if (sae->tmp == NULL ||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
- password_len,
- identifier) < 0) ||
+ password_len) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
- password_len,
- identifier) < 0) ||
- sae_derive_commit(sae) < 0)
+ password_len) < 0))
return -1;
- return 0;
+
+ sae->h2e = 0;
+ sae->pk = 0;
+ return sae_derive_commit(sae);
+}
+
+
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups, const struct sae_pk *pk)
+{
+ if (!sae->tmp)
+ return -1;
+
+ while (pt) {
+ if (pt->group == sae->group)
+ break;
+ pt = pt->next;
+ }
+ if (!pt) {
+ wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
+ sae->group);
+ return -1;
+ }
+
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
+ sae->tmp->ssid_len = pt->ssid_len;
+ sae->tmp->ap_pk = pk;
+#endif /* CONFIG_SAE_PK */
+ sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
+ wpabuf_free(sae->tmp->own_rejected_groups);
+ sae->tmp->own_rejected_groups = NULL;
+ if (rejected_groups) {
+ int count, i;
+ struct wpabuf *groups;
+
+ count = int_array_len(rejected_groups);
+ groups = wpabuf_alloc(count * 2);
+ if (!groups)
+ return -1;
+ for (i = 0; i < count; i++)
+ wpabuf_put_le16(groups, rejected_groups[i]);
+ sae->tmp->own_rejected_groups = groups;
+ }
+
+ if (pt->ec) {
+ crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
+ sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ecc)
+ return -1;
+ }
+
+ if (pt->dh) {
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ffc)
+ return -1;
+ }
+
+ sae->h2e = 1;
+ return sae_derive_commit(sae);
}
@@ -685,32 +1484,102 @@ fail:
}
+static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
+ const u8 *context, size_t context_len,
+ u8 *out, size_t out_len)
+{
+ if (hash_len == 32)
+ return sha256_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
static int sae_derive_keys(struct sae_data *sae, const u8 *k)
{
- u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
- u8 keyseed[SHA256_MAC_LEN];
- u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
+ const u8 *salt;
+ struct wpabuf *rejected_groups = NULL;
+ u8 keyseed[SAE_MAX_HASH_LEN];
+ u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
+ size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+ const u8 *addr[1];
+ size_t len[1];
tmp = crypto_bignum_init();
if (tmp == NULL)
goto fail;
- /* keyseed = H(<0>32, k)
- * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ /* keyseed = H(salt, k)
+ * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+ *
+ * When SAE-PK is used,
+ * KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
*/
+ if (!sae->h2e)
+ hash_len = SHA256_MAC_LEN;
+ else if (sae->tmp->dh)
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ else
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ if (sae->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
+ struct wpabuf *own, *peer;
+
+ own = sae->tmp->own_rejected_groups;
+ peer = sae->tmp->peer_rejected_groups;
+ salt_len = 0;
+ if (own)
+ salt_len += wpabuf_len(own);
+ if (peer)
+ salt_len += wpabuf_len(peer);
+ rejected_groups = wpabuf_alloc(salt_len);
+ if (!rejected_groups)
+ goto fail;
+ if (sae->tmp->own_addr_higher) {
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ } else {
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ }
+ salt = wpabuf_head(rejected_groups);
+ salt_len = wpabuf_len(rejected_groups);
+ } else {
+ os_memset(zero, 0, hash_len);
+ salt = zero;
+ salt_len = hash_len;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
+ salt, salt_len);
+ addr[0] = k;
+ len[0] = prime_len;
+ if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
- os_memset(null_key, 0, sizeof(null_key));
- hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
- keyseed);
- wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
-
- crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
- tmp);
- crypto_bignum_mod(tmp, sae->tmp->order, tmp);
+ if (crypto_bignum_add(sae->tmp->own_commit_scalar,
+ sae->peer_commit_scalar, tmp) < 0 ||
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
+ goto fail;
/* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
* string that is needed for KCK, PMK, and PMKID derivation, but it
* seems to make most sense to encode the
@@ -719,19 +1588,48 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->order_len, keys, sizeof(keys)) < 0)
+
+#ifdef CONFIG_SAE_PK
+ if (sae->pk) {
+ if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
+ val, sae->tmp->order_len,
+ keys, 2 * hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ } else {
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ }
+#else /* CONFIG_SAE_PK */
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
- os_memset(keyseed, 0, sizeof(keyseed));
- os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
- os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+#endif /* !CONFIG_SAE_PK */
+
+ forced_memzero(keyseed, sizeof(keyseed));
+ os_memcpy(sae->tmp->kck, keys, hash_len);
+ sae->tmp->kck_len = hash_len;
+ os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
- os_memset(keys, 0, sizeof(keys));
- wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+#ifdef CONFIG_SAE_PK
+ if (sae->pk) {
+ os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
+ hash_len);
+ sae->tmp->kek_len = hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
+ sae->tmp->kek, sae->tmp->kek_len);
+ }
+#endif /* CONFIG_SAE_PK */
+ forced_memzero(keys, sizeof(keys));
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
+ sae->tmp->kck, sae->tmp->kck_len);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
ret = 0;
fail:
+ wpabuf_free(rejected_groups);
crypto_bignum_deinit(tmp, 0);
return ret;
}
@@ -749,38 +1647,42 @@ int sae_process_commit(struct sae_data *sae)
}
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token, const char *identifier)
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token, const char *identifier)
{
u8 *pos;
if (sae->tmp == NULL)
- return;
+ return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (token) {
+ if (!sae->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
}
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
pos, sae->tmp->prime_len);
if (sae->tmp->ec) {
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec,
- sae->tmp->own_commit_element_ecc,
- pos, pos + sae->tmp->prime_len);
+ if (crypto_ec_point_to_bin(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ pos, pos + sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len);
} else {
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+ sae->tmp->prime_len,
+ sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
@@ -794,6 +1696,28 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
identifier);
}
+
+ if (sae->h2e && sae->tmp->own_rejected_groups) {
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
+ sae->tmp->own_rejected_groups);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf,
+ 1 + wpabuf_len(sae->tmp->own_rejected_groups));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
+ wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
+ }
+
+ if (sae->h2e && token) {
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(token));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ wpabuf_put_buf(buf, token);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "SAE: Anti-clogging token (in container)",
+ token);
+ }
+
+ return 0;
}
@@ -849,30 +1773,44 @@ static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
}
+static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 2 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
+}
+
+
+static int sae_is_token_container_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
- size_t *token_len)
+ size_t *token_len, int h2e)
{
size_t scalar_elem_len, tlen;
- const u8 *elem;
if (token)
*token = NULL;
if (token_len)
*token_len = 0;
+ if (h2e)
+ return; /* No Anti-Clogging Token field outside container IE */
+
scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
if (scalar_elem_len >= (size_t) (end - *pos))
return; /* No extra data beyond peer scalar and element */
- /* It is a bit difficult to parse this now that there is an
- * optional variable length Anti-Clogging Token field and
- * optional variable length Password Identifier element in the
- * frame. We are sending out fixed length Anti-Clogging Token
- * fields, so use that length as a requirement for the received
- * token and check for the presence of possible Password
- * Identifier element based on the element header information.
- */
tlen = end - (*pos + scalar_elem_len);
if (tlen < SHA256_MAC_LEN) {
@@ -882,21 +1820,6 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
return;
}
- elem = *pos + scalar_elem_len;
- if (sae_is_password_id_elem(elem, end)) {
- /* Password Identifier element takes out all available
- * extra octets, so there can be no Anti-Clogging token in
- * this frame. */
- return;
- }
-
- elem += SHA256_MAC_LEN;
- if (sae_is_password_id_elem(elem, end)) {
- /* Password Identifier element is included in the end, so
- * remove its length from the Anti-Clogging token field. */
- tlen -= 2 + elem[1];
- }
-
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
if (token)
*token = *pos;
@@ -906,6 +1829,21 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
}
+static void sae_parse_token_container(struct sae_data *sae,
+ const u8 *pos, const u8 *end,
+ const u8 **token, size_t *token_len)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_token_container_elem(pos, end))
+ return;
+ *token = pos + 3;
+ *token_len = pos[1] - 1;
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
+ *token, *token_len);
+}
+
+
static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
@@ -926,8 +1864,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
* shall be dropped if the peer-scalar is identical to the one used in
* the existing protocol instance.
*/
- if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
- crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+ if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted &&
+ crypto_bignum_cmp(sae->peer_commit_scalar_accepted,
+ peer_scalar) == 0) {
wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
"peer-commit-scalar");
crypto_bignum_deinit(peer_scalar, 0);
@@ -1061,11 +2000,14 @@ static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
static int sae_parse_password_identifier(struct sae_data *sae,
- const u8 *pos, const u8 *end)
+ const u8 **pos, const u8 *end)
{
+ const u8 *epos;
+ u8 len;
+
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- pos, end - pos);
- if (!sae_is_password_id_elem(pos, end)) {
+ *pos, end - *pos);
+ if (!sae_is_password_id_elem(*pos, end)) {
if (sae->tmp->pw_id) {
wpa_printf(MSG_DEBUG,
"SAE: No Password Identifier included, but expected one (%s)",
@@ -1077,9 +2019,17 @@ static int sae_parse_password_identifier(struct sae_data *sae,
return WLAN_STATUS_SUCCESS; /* No Password Identifier */
}
+ epos = *pos;
+ epos++; /* skip IE type */
+ len = *epos++; /* IE length */
+ if (len > end - epos || len < 1)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ epos++; /* skip ext ID */
+ len--;
+
if (sae->tmp->pw_id &&
- (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
- os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+ (len != os_strlen(sae->tmp->pw_id) ||
+ os_memcmp(sae->tmp->pw_id, epos, len) != 0)) {
wpa_printf(MSG_DEBUG,
"SAE: The included Password Identifier does not match the expected one (%s)",
sae->tmp->pw_id);
@@ -1087,19 +2037,52 @@ static int sae_parse_password_identifier(struct sae_data *sae,
}
os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = os_malloc(pos[1]);
+ sae->tmp->pw_id = os_malloc(len + 1);
if (!sae->tmp->pw_id)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
- sae->tmp->pw_id[pos[1] - 1] = '\0';
+ os_memcpy(sae->tmp->pw_id, epos, len);
+ sae->tmp->pw_id[len] = '\0';
wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
- sae->tmp->pw_id, pos[1] - 1);
+ sae->tmp->pw_id, len);
+ *pos = epos + len;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int sae_parse_rejected_groups(struct sae_data *sae,
+ const u8 **pos, const u8 *end)
+{
+ const u8 *epos;
+ u8 len;
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ *pos, end - *pos);
+ if (!sae_is_rejected_groups_elem(*pos, end))
+ return WLAN_STATUS_SUCCESS;
+
+ epos = *pos;
+ epos++; /* skip IE type */
+ len = *epos++; /* IE length */
+ if (len > end - epos || len < 1)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ epos++; /* skip ext ID */
+ len--;
+
+ wpabuf_free(sae->tmp->peer_rejected_groups);
+ sae->tmp->peer_rejected_groups = wpabuf_alloc(len);
+ if (!sae->tmp->peer_rejected_groups)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_put_data(sae->tmp->peer_rejected_groups, epos, len);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
+ sae->tmp->peer_rejected_groups);
+ *pos = epos + len;
return WLAN_STATUS_SUCCESS;
}
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups)
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e)
{
const u8 *pos = data, *end = data + len;
u16 res;
@@ -1113,7 +2096,7 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
pos += 2;
/* Optional Anti-Clogging Token */
- sae_parse_commit_token(sae, &pos, end, token, token_len);
+ sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
/* commit-scalar */
res = sae_parse_commit_scalar(sae, &pos, end);
@@ -1126,10 +2109,21 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* Optional Password Identifier element */
- res = sae_parse_password_identifier(sae, pos, end);
+ res = sae_parse_password_identifier(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
+ /* Conditional Rejected Groups element */
+ if (h2e) {
+ res = sae_parse_rejected_groups(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ }
+
+ /* Optional Anti-Clogging Token Container element */
+ if (h2e)
+ sae_parse_token_container(sae, pos, end, token, token_len);
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
@@ -1157,12 +2151,12 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
}
-static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const u8 *element1, size_t element1_len,
- const struct crypto_bignum *scalar2,
- const u8 *element2, size_t element2_len,
- u8 *confirm)
+static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
{
const u8 *addr[5];
size_t len[5];
@@ -1176,139 +2170,168 @@ static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
* verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
* PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
*/
+ if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len) < 0)
+ return -1;
addr[0] = sc;
len[0] = 2;
- crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
- sae->tmp->prime_len);
addr[1] = scalar_b1;
len[1] = sae->tmp->prime_len;
addr[2] = element1;
len[2] = element1_len;
- crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
- sae->tmp->prime_len);
addr[3] = scalar_b2;
len[3] = sae->tmp->prime_len;
addr[4] = element2;
len[4] = element2_len;
- hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
- confirm);
+ return hkdf_extract(sae->tmp->kck_len, sae->tmp->kck, sae->tmp->kck_len,
+ 5, addr, len, confirm);
}
-static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_ec_point *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_ec_point *element2,
- u8 *confirm)
+static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
{
u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
- crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
- element_b1 + sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
- element_b2 + sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
- scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+ if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len) < 0 ||
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1,
+ 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
-static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_bignum *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_bignum *element2,
- u8 *confirm)
+static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
{
u8 element_b1[SAE_MAX_PRIME_LEN];
u8 element_b2[SAE_MAX_PRIME_LEN];
- crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
- sae->tmp->prime_len);
- crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
- sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
- scalar2, element_b2, sae->tmp->prime_len, confirm);
+ if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
+ size_t hash_len;
+ int res;
if (sae->tmp == NULL)
- return;
+ return -1;
+
+ hash_len = sae->tmp->kck_len;
/* Send-Confirm */
- sc = wpabuf_put(buf, 0);
- wpabuf_put_le16(buf, sae->send_confirm);
if (sae->send_confirm < 0xffff)
sae->send_confirm++;
+ sc = wpabuf_put(buf, 0);
+ wpabuf_put_le16(buf, sae->send_confirm);
if (sae->tmp->ec)
- sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ wpabuf_put(buf, hash_len));
else
- sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ res = sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ wpabuf_put(buf, hash_len));
+ if (res)
+ return res;
+
+#ifdef CONFIG_SAE_PK
+ if (sae_write_confirm_pk(sae, buf) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
+ return 0;
}
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
{
- u8 verifier[SHA256_MAC_LEN];
+ u8 verifier[SAE_MAX_HASH_LEN];
+ size_t hash_len;
- if (len < 2 + SHA256_MAC_LEN) {
+ if (!sae->tmp)
+ return -1;
+
+ hash_len = sae->tmp->kck_len;
+ if (len < 2 + hash_len) {
wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
return -1;
}
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (!sae->tmp || !sae->peer_commit_scalar ||
- !sae->tmp->own_commit_scalar) {
+ if (!sae->peer_commit_scalar || !sae->tmp->own_commit_scalar) {
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
return -1;
}
if (sae->tmp->ec) {
if (!sae->tmp->peer_commit_element_ecc ||
- !sae->tmp->own_commit_element_ecc)
+ !sae->tmp->own_commit_element_ecc ||
+ sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- verifier);
} else {
if (!sae->tmp->peer_commit_element_ffc ||
- !sae->tmp->own_commit_element_ffc)
+ !sae->tmp->own_commit_element_ffc ||
+ sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ verifier) < 0)
return -1;
- sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- verifier);
}
- if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
- data + 2, SHA256_MAC_LEN);
+ data + 2, hash_len);
wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
- verifier, SHA256_MAC_LEN);
+ verifier, hash_len);
return -1;
}
+#ifdef CONFIG_SAE_PK
+ if (sae_check_confirm_pk(sae, data + 2 + hash_len,
+ len - 2 - hash_len) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
diff --git a/contrib/wpa/src/common/sae.h b/contrib/wpa/src/common/sae.h
index 10f9302e3d63..93fc5fb39712 100644
--- a/contrib/wpa/src/common/sae.h
+++ b/contrib/wpa/src/common/sae.h
@@ -12,17 +12,34 @@
#define SAE_KCK_LEN 32
#define SAE_PMK_LEN 32
#define SAE_PMKID_LEN 16
-#define SAE_KEYSEED_KEY_LEN 32
#define SAE_MAX_PRIME_LEN 512
#define SAE_MAX_ECC_PRIME_LEN 66
-#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
-#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+#define SAE_MAX_HASH_LEN 64
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#ifdef CONFIG_SAE_PK
+#define SAE_CONFIRM_MAX_LEN ((2 + SAE_MAX_HASH_LEN) + 1500)
+#else /* CONFIG_SAE_PK */
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
+#endif /* CONFIG_SAE_PK */
+#define SAE_PK_M_LEN 16
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
+struct sae_pk {
+ struct wpabuf *m;
+ struct crypto_ec_key *key;
+ int group;
+ struct wpabuf *pubkey; /* DER encoded subjectPublicKey */
+#ifdef CONFIG_TESTING_OPTIONS
+ struct crypto_ec_key *sign_key_override;
+#endif /* CONFIG_TESTING_OPTIONS */
+};
+
+
struct sae_temporary_data {
- u8 kck[SAE_KCK_LEN];
+ u8 kck[SAE_MAX_HASH_LEN];
+ size_t kck_len;
struct crypto_bignum *own_commit_scalar;
struct crypto_bignum *own_commit_element_ffc;
struct crypto_ec_point *own_commit_element_ecc;
@@ -43,6 +60,41 @@ struct sae_temporary_data {
char *pw_id;
int vlan_id;
u8 bssid[ETH_ALEN];
+ struct wpabuf *own_rejected_groups;
+ struct wpabuf *peer_rejected_groups;
+ unsigned int own_addr_higher:1;
+
+#ifdef CONFIG_SAE_PK
+ u8 kek[SAE_MAX_HASH_LEN];
+ size_t kek_len;
+ const struct sae_pk *ap_pk;
+ u8 own_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
+ u8 fingerprint[SAE_MAX_HASH_LEN];
+ size_t fingerprint_bytes;
+ size_t fingerprint_bits;
+ size_t lambda;
+ unsigned int sec;
+ u8 ssid[32];
+ size_t ssid_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool omit_pk_elem;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
+};
+
+struct sae_pt {
+ struct sae_pt *next;
+ int group;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *ecc_pt;
+
+ const struct dh_group *dh;
+ struct crypto_bignum *ffc_pt;
+#ifdef CONFIG_SAE_PK
+ u8 ssid[32];
+ size_t ssid_len;
+#endif /* CONFIG_SAE_PK */
};
enum sae_state {
@@ -55,9 +107,12 @@ struct sae_data {
u8 pmk[SAE_PMK_LEN];
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
+ struct crypto_bignum *peer_commit_scalar_accepted;
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
+ unsigned int h2e:1;
+ unsigned int pk:1;
struct sae_temporary_data *tmp;
};
@@ -67,15 +122,51 @@ void sae_clear_data(struct sae_data *sae);
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- const char *identifier, struct sae_data *sae);
+ struct sae_data *sae);
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups, const struct sae_pk *pk);
int sae_process_commit(struct sae_data *sae);
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token, const char *identifier);
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups);
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e);
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len);
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len);
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier);
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+void sae_deinit_pt(struct sae_pt *pt);
+
+/* sae_pk.c */
+#ifdef CONFIG_SAE_PK
+bool sae_pk_valid_password(const char *pw);
+#else /* CONFIG_SAE_PK */
+static inline bool sae_pk_valid_password(const char *pw)
+{
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+char * sae_pk_base32_encode(const u8 *src, size_t len_bits);
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len);
+int sae_pk_set_password(struct sae_data *sae, const char *password);
+void sae_deinit_pk(struct sae_pk *pk);
+struct sae_pk * sae_parse_pk(const char *val);
+int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf);
+int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len);
+int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash);
+u32 sae_pk_get_be19(const u8 *buf);
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len);
#endif /* SAE_H */
diff --git a/contrib/wpa/src/common/sae_pk.c b/contrib/wpa/src/common/sae_pk.c
new file mode 100644
index 000000000000..df79e5f2c3b0
--- /dev/null
+++ b/contrib/wpa/src/common/sae_pk.c
@@ -0,0 +1,884 @@
+/*
+ * SAE-PK
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <stdint.h>
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/crypto.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "sae.h"
+
+
+/* RFC 4648 base 32 alphabet with lowercase characters */
+static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
+
+
+static const u8 d_mult_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
+ 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
+ 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
+ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+ 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
+ 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
+ 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
+ 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
+ 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
+ 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
+ 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
+ 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
+ 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
+ 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
+ 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
+ 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
+ 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
+ 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
+ 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
+ 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
+ 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
+ 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
+ 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
+ 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
+ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
+ 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
+ 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static const u8 d_perm_table[] = {
+ 7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
+ 22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
+};
+
+
+static u8 d_permute(u8 val, unsigned int iter)
+{
+ if (iter == 0)
+ return val;
+ return d_permute(d_perm_table[val], iter - 1);
+}
+
+
+static u8 d_invert(u8 val)
+{
+ if (val > 0 && val < 16)
+ return 16 - val;
+ return val;
+}
+
+
+static char d_check_char(const char *str, size_t len)
+{
+ size_t i;
+ u8 val = 0;
+ u8 dtable[256];
+ unsigned int iter = 1;
+ int j;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ for (j = len - 1; j >= 0; j--) {
+ u8 c, p;
+
+ c = dtable[(u8) str[j]];
+ if (c == 0x80)
+ continue;
+ p = d_permute(c, iter);
+ iter++;
+ val = d_mult_table[val * 32 + p];
+ }
+
+ return sae_pk_base32_table[d_invert(val)];
+}
+
+
+bool sae_pk_valid_password(const char *pw)
+{
+ int pos;
+ size_t i, pw_len = os_strlen(pw);
+ u8 sec_1b;
+ u8 dtable[256];
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ /* SAE-PK password has at least three four character components
+ * separated by hyphens. */
+ if (pw_len < 14 || pw_len % 5 != 4) {
+ wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
+ return false;
+ }
+
+ for (pos = 0; pw[pos]; pos++) {
+ if (pos && pos % 5 == 4) {
+ if (pw[pos] != '-') {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (separator)");
+ return false;
+ }
+ continue;
+ }
+ if (dtable[(u8) pw[pos]] == 0x80) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (character)");
+ return false;
+ }
+ }
+
+ /* Verify that the checksum character is valid */
+ if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (checksum)");
+ return false;
+ }
+
+ /* Verify that Sec_1b bits match */
+ sec_1b = dtable[(u8) pw[0]] & BIT(4);
+ for (i = 5; i < pw_len; i += 5) {
+ if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (Sec_1b)");
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
+{
+ if (*bits == 0)
+ return pos;
+ if (*bits > 5)
+ *bits -= 5;
+ else
+ *bits = 0;
+
+ if ((pos - start) % 5 == 4)
+ *pos++ = '-';
+ *pos++ = sae_pk_base32_table[idx];
+ return pos;
+}
+
+
+/* Base32 encode a password and add hyper separators and checksum */
+char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
+{
+ char *out, *pos;
+ size_t olen, extra_pad, i;
+ u64 block = 0;
+ u8 val;
+ size_t len = (len_bits + 7) / 8;
+ size_t left = len_bits;
+ int j;
+
+ if (len == 0 || len >= SIZE_MAX / 8)
+ return NULL;
+ olen = len * 8 / 5 + 1;
+ olen += olen / 4; /* hyphen separators */
+ pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
+ if (!out)
+ return NULL;
+
+ extra_pad = (5 - len % 5) % 5;
+ for (i = 0; i < len + extra_pad; i++) {
+ val = i < len ? src[i] : 0;
+ block <<= 8;
+ block |= val;
+ if (i % 5 == 4) {
+ for (j = 7; j >= 0; j--)
+ pos = add_char(out, pos,
+ (block >> j * 5) & 0x1f, &left);
+ block = 0;
+ }
+ }
+
+ *pos = d_check_char(out, os_strlen(out));
+
+ return out;
+}
+
+
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
+{
+ u8 dtable[256], *out, *pos, tmp;
+ u64 block = 0;
+ size_t i, count, olen;
+ int pad = 0;
+ size_t extra_pad;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[(u8) src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0)
+ return NULL;
+ extra_pad = (8 - count % 8) % 8;
+
+ olen = (count + extra_pad) / 8 * 5;
+ pos = out = os_malloc(olen);
+ if (!out)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len + extra_pad; i++) {
+ u8 val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
+ if (tmp == 0x80)
+ continue;
+
+ if (val == '=')
+ pad++;
+ block <<= 5;
+ block |= tmp;
+ count++;
+ if (count == 8) {
+ *pos++ = (block >> 32) & 0xff;
+ *pos++ = (block >> 24) & 0xff;
+ *pos++ = (block >> 16) & 0xff;
+ *pos++ = (block >> 8) & 0xff;
+ *pos++ = block & 0xff;
+ count = 0;
+ block = 0;
+ if (pad) {
+ /* Leave in all the available bits with zero
+ * padding to full octets from right. */
+ pos -= pad * 5 / 8;
+ break;
+ }
+ }
+ }
+
+ *out_len = pos - out;
+ return out;
+}
+
+
+u32 sae_pk_get_be19(const u8 *buf)
+{
+ return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
+}
+
+
+/* shift left by two octets and three bits; fill in zeros from right;
+ * len must be at least three */
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf + 2;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 3) | (src[1] >> 5);
+ src++;
+ }
+ *dst++ = *src << 3;
+ *dst++ = 0;
+ *dst++ = 0;
+}
+
+
+static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 1) | (src[1] >> 7);
+ src++;
+ }
+ *dst++ = *src << 1;
+}
+
+
+int sae_pk_set_password(struct sae_data *sae, const char *password)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ size_t len, pw_len;
+ u8 *pw, *pos;
+ int bits;
+ u32 val = 0, val19;
+ unsigned int val_bits = 0;
+
+ if (!tmp)
+ return -1;
+
+ os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
+ tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
+
+ len = os_strlen(password);
+ if (len < 1 || !sae_pk_valid_password(password))
+ return -1;
+
+ pw = sae_pk_base32_decode(password, len, &pw_len);
+ if (!pw)
+ return -1;
+
+ tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
+ tmp->lambda = len - len / 5;
+ tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
+ wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
+ tmp->sec, tmp->lambda, tmp->fingerprint_bits);
+
+ /* Construct Fingerprint from PasswordBase by prefixing with Sec zero
+ * octets and skipping the Sec_1b bits */
+ pos = &tmp->fingerprint[tmp->sec];
+ bits = tmp->fingerprint_bits - 8 * tmp->sec;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
+ while (bits > 0) {
+ if (val_bits < 8) {
+ sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
+ val19 = sae_pk_get_be19(pw);
+ sae_pk_buf_shift_left_19(pw, pw_len);
+ val = (val << 19) | val19;
+ val_bits += 19;
+ }
+ if (val_bits >= 8) {
+ if (bits < 8)
+ break;
+ *pos++ = (val >> (val_bits - 8)) & 0xff;
+ val_bits -= 8;
+ bits -= 8;
+ }
+ }
+ if (bits > 0) {
+ val >>= val_bits - bits;
+ *pos++ = val << (8 - bits);
+ }
+ tmp->fingerprint_bytes = pos - tmp->fingerprint;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
+ bin_clear_free(pw, pw_len);
+ return 0;
+}
+
+
+static size_t sae_group_2_hash_len(int group)
+{
+ switch (group) {
+ case 19:
+ return 32;
+ case 20:
+ return 48;
+ case 21:
+ return 64;
+ }
+
+ return 0;
+}
+
+
+void sae_deinit_pk(struct sae_pk *pk)
+{
+ if (pk) {
+ wpabuf_free(pk->m);
+ crypto_ec_key_deinit(pk->key);
+#ifdef CONFIG_TESTING_OPTIONS
+ crypto_ec_key_deinit(pk->sign_key_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpabuf_free(pk->pubkey);
+ os_free(pk);
+ }
+}
+
+
+struct sae_pk * sae_parse_pk(const char *val)
+{
+ struct sae_pk *pk;
+ const char *pos;
+#ifdef CONFIG_TESTING_OPTIONS
+ const char *pos2;
+#endif /* CONFIG_TESTING_OPTIONS */
+ size_t len;
+ unsigned char *der;
+ size_t der_len, b_len;
+
+ /* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
+
+ pos = os_strchr(val, ':');
+ if (!pos || (pos - val) & 0x01)
+ return NULL;
+ len = (pos - val) / 2;
+ if (len != SAE_PK_M_LEN) {
+ wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
+ len);
+ return NULL;
+ }
+
+ pk = os_zalloc(sizeof(*pk));
+ if (!pk)
+ return NULL;
+ pk->m = wpabuf_alloc(len);
+ if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
+ wpa_printf(MSG_INFO, "SAE: Failed to parse m");
+ goto fail;
+ }
+
+ pos++;
+ b_len = os_strlen(pos);
+#ifdef CONFIG_TESTING_OPTIONS
+ pos2 = os_strchr(pos, ':');
+ if (pos2) {
+ b_len = pos2 - pos;
+ pos2++;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ der = base64_decode(pos, b_len, &der_len);
+ if (!der) {
+ wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
+ goto fail;
+ }
+
+ pk->key = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->key)
+ goto fail;
+ pk->group = crypto_ec_key_group(pk->key);
+ pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
+ if (!pk->pubkey)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (pos2) {
+ der = base64_decode(pos2, os_strlen(pos2), &der_len);
+ if (!der) {
+ wpa_printf(MSG_INFO,
+ "SAE: Failed to base64 decode PK key");
+ goto fail;
+ }
+
+ pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->sign_key_override)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return pk;
+fail:
+ sae_deinit_pk(pk);
+ return NULL;
+}
+
+
+int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
+{
+ if (hash_len == 32)
+ return sha256_vector(1, &data, &len, hash);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
+ bool ap, const u8 *m, size_t m_len,
+ const u8 *pubkey, size_t pubkey_len, u8 *hash)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ struct wpabuf *sig_data;
+ u8 *pos;
+ int ret = -1;
+
+ /* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
+ * M || K_AP || AP-BSSID || STA-MAC */
+ sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
+ 2 * ETH_ALEN);
+ if (!sig_data)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
+ tmp->peer_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
+ tmp->own_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
+ sae->peer_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
+ tmp->own_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0)
+ goto fail;
+ wpabuf_put_data(sig_data, m, m_len);
+ wpabuf_put_data(sig_data, pubkey, pubkey_len);
+ wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
+ ETH_ALEN);
+ wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
+ ETH_ALEN);
+ wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
+ sig_data);
+ if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
+ hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
+ hash, hash_len);
+ ret = 0;
+fail:
+ wpabuf_free(sig_data);
+ return ret;
+}
+
+
+int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ struct wpabuf *sig = NULL;
+ size_t need;
+ int ret = -1;
+ u8 *encr_mod;
+ size_t encr_mod_len;
+ const struct sae_pk *pk;
+ u8 hash[SAE_MAX_HASH_LEN];
+ size_t hash_len;
+ struct crypto_ec_key *key;
+
+ if (!tmp)
+ return -1;
+
+ pk = tmp->ap_pk;
+ if (!sae->pk || !pk)
+ return 0;
+
+ key = pk->key;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (tmp->omit_pk_elem)
+ return 0;
+ if (pk->sign_key_override) {
+ wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
+ key = pk->sign_key_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for writing confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ hash_len = sae_group_2_hash_len(pk->group);
+ if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
+ wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
+ wpabuf_len(pk->pubkey), hash) < 0)
+ goto fail;
+ sig = crypto_ec_key_sign(key, hash, hash_len);
+ if (!sig)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
+
+ /* TODO: fragmentation if any of the elements needs it for a group
+ * using sufficiently large primes (none of the currently supported
+ * ones do) */
+
+ encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
+ need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
+ 6 + encr_mod_len;
+ if (wpabuf_tailroom(buf) < need) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
+ wpabuf_tailroom(buf), need);
+ goto fail;
+ }
+
+ /* FILS Public Key element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
+ wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
+ wpabuf_put_buf(buf, pk->pubkey);
+
+ /* FILS Key Confirmation element (KeyAuth) */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ /* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
+ * AP-BSSID || STA-MAC) */
+ wpabuf_put_buf(buf, sig);
+
+ /* SAE-PK element */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + encr_mod_len);
+ wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
+ /* EncryptedModifier = AES-SIV-Q(M); no AAD */
+ encr_mod = wpabuf_put(buf, encr_mod_len);
+ if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
+ wpabuf_head(pk->m), wpabuf_len(pk->m),
+ 0, NULL, NULL, encr_mod) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ encr_mod, encr_mod_len);
+
+ ret = 0;
+fail:
+ wpabuf_free(sig);
+ return ret;
+
+}
+
+
+static bool sae_pk_valid_fingerprint(struct sae_data *sae,
+ const u8 *m, size_t m_len,
+ const u8 *k_ap, size_t k_ap_len, int group)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ u8 *hash_data, *pos;
+ size_t hash_len, hash_data_len;
+ u8 hash[SAE_MAX_HASH_LEN];
+ int res;
+
+ if (!tmp->fingerprint_bytes) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: No PW available for K_AP fingerprint check");
+ return false;
+ }
+
+ /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
+ */
+
+ hash_len = sae_group_2_hash_len(group);
+ hash_data_len = tmp->ssid_len + m_len + k_ap_len;
+ hash_data = os_malloc(hash_data_len);
+ if (!hash_data)
+ return false;
+ pos = hash_data;
+ os_memcpy(pos, tmp->ssid, tmp->ssid_len);
+ pos += tmp->ssid_len;
+ os_memcpy(pos, m, m_len);
+ pos += m_len;
+ os_memcpy(pos, k_ap, k_ap_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
+ hash_data, hash_data_len);
+ res = sae_hash(hash_len, hash_data, hash_data_len, hash);
+ bin_clear_free(hash_data, hash_data_len);
+ if (res < 0)
+ return false;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
+ hash, hash_len);
+
+ if (tmp->fingerprint_bits > hash_len * 8) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not enough hash output bits for the fingerprint");
+ return false;
+ }
+ if (tmp->fingerprint_bits % 8) {
+ size_t extra;
+
+ /* Zero out the extra bits in the last octet */
+ extra = 8 - tmp->fingerprint_bits % 8;
+ pos = &hash[tmp->fingerprint_bits / 8];
+ *pos = (*pos >> extra) << extra;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
+ tmp->fingerprint_bytes);
+ res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
+ return false;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
+ return true;
+}
+
+
+int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ const u8 *k_ap;
+ u8 m[SAE_PK_M_LEN];
+ size_t k_ap_len;
+ struct crypto_ec_key *key;
+ int res;
+ u8 hash[SAE_MAX_HASH_LEN];
+ size_t hash_len;
+ int group;
+ struct ieee802_11_elems elems;
+
+ if (!tmp)
+ return -1;
+ if (!sae->pk || tmp->ap_pk)
+ return 0;
+
+ if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for checking confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
+ return -1;
+ }
+ if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not all mandatory IEs included in confirm");
+ return -1;
+ }
+
+ /* TODO: Fragment reassembly */
+
+ if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room for EncryptedModifier in SAE-PK element");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
+
+ if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
+ 0, NULL, NULL, m) < 0) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Failed to decrypt EncryptedModifier");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
+
+ if (elems.fils_pk[0] != 2) {
+ wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
+ elems.fils_pk[0]);
+ return -1;
+ }
+ k_ap_len = elems.fils_pk_len - 1;
+ k_ap = elems.fils_pk + 1;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
+ /* TODO: Check against the public key, if one is stored in the network
+ * profile */
+
+ key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
+ if (!key) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
+ return -1;
+ }
+
+ group = crypto_ec_key_group(key);
+ if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
+ group)) {
+ crypto_ec_key_deinit(key);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
+ elems.fils_key_confirm, elems.fils_key_confirm_len);
+
+ hash_len = sae_group_2_hash_len(group);
+ if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
+ k_ap, k_ap_len, hash) < 0) {
+ crypto_ec_key_deinit(key);
+ return -1;
+ }
+
+ res = crypto_ec_key_verify_signature(key, hash, hash_len,
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ crypto_ec_key_deinit(key);
+
+ if (res != 1) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Invalid or incorrect signature in KeyAuth");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
+
+ /* TODO: Store validated public key into network profile */
+
+ return 0;
+}
diff --git a/contrib/wpa/src/common/version.h b/contrib/wpa/src/common/version.h
index c2a3a80d7f71..0235c9bf6776 100644
--- a/contrib/wpa/src/common/version.h
+++ b/contrib/wpa/src/common/version.h
@@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
-#define VERSION_STR "2.9" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.10-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/contrib/wpa/src/common/wpa_common.c b/contrib/wpa/src/common/wpa_common.c
index 64e5c5f4cd84..04461516f138 100644
--- a/contrib/wpa/src/common/wpa_common.c
+++ b/contrib/wpa/src/common/wpa_common.c
@@ -212,11 +212,9 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
#ifdef CONFIG_SAE
@@ -335,6 +333,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
* @ptk: Buffer for pairwise transient key
* @akmp: Negotiated AKM
* @cipher: Negotiated pairwise cipher
+ * @kdk_len: The length in octets that should be derived for KDK
* Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -350,13 +349,22 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len)
+ const u8 *z, size_t z_len, size_t kdk_len)
{
#define MAX_Z_LEN 66 /* with NIST P-521 */
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
- u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len;
+#ifdef CONFIG_OWE
+ int owe_ptk_workaround = 0;
+
+ if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
+ owe_ptk_workaround = 1;
+ akmp = WPA_KEY_MGMT_OWE;
+ }
+#endif /* CONFIG_OWE */
if (pmk_len == 0) {
wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
@@ -389,16 +397,24 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
data_len += z_len;
}
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "WPA: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
ptk->kek_len = wpa_kek_len(akmp, pmk_len);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
if (ptk->tk_len == 0) {
wpa_printf(MSG_ERROR,
"WPA: Unsupported cipher (0x%x) used in PTK derivation",
cipher);
return -1;
}
- ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len;
if (wpa_key_mgmt_sha384(akmp)) {
#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
@@ -409,15 +425,33 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
#else /* CONFIG_SUITEB192 || CONFIG_FILS */
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
- } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ } else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
-#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+#ifdef CONFIG_OWE
+ } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
+ owe_ptk_workaround)) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE) {
+ wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
+ (unsigned int) pmk_len);
return -1;
-#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -464,6 +498,12 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len +
+ ptk->tk_len, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
+ }
+
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -552,15 +592,16 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len)
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len)
{
u8 *data, *pos;
size_t data_len;
u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
- FILS_FT_MAX_LEN];
+ FILS_FT_MAX_LEN + WPA_KDK_MAX_LEN];
size_t key_data_len;
const char *label = "FILS PTK Derivation";
int ret = -1;
+ size_t offset;
/*
* FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
@@ -571,6 +612,9 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
* If doing FT initial mobility domain association:
* FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
* FILS-FT_bits)
+ * When a KDK is derived:
+ * KDK = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits + FILS-FT_bits,
+ * KDK_bits)
*/
data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
data = os_malloc(data_len);
@@ -599,6 +643,19 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
goto err;
key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
+ if (kdk_len) {
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "FILS: KDK len=%zu too big",
+ kdk_len);
+ goto err;
+ }
+
+ ptk->kdk_len = kdk_len;
+ key_data_len += kdk_len;
+ } else {
+ ptk->kdk_len = 0;
+ }
+
if (fils_ft && fils_ft_len) {
if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
*fils_ft_len = 32;
@@ -633,19 +690,27 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
os_memcpy(ick, tmp, *ick_len);
+ offset = *ick_len;
wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
- os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
+ os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
+ offset += ptk->kek_len;
- os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
+ os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
+ offset += ptk->tk_len;
if (fils_ft && fils_ft_len) {
- os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
- *fils_ft_len);
+ os_memcpy(fils_ft, tmp + offset, *fils_ft_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
fils_ft, *fils_ft_len);
+ offset += *fils_ft_len;
+ }
+
+ if (ptk->kdk_len) {
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KDK", ptk->kdk, ptk->kdk_len);
}
ptk->kek2_len = 0;
@@ -692,7 +757,7 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
len[2] = ETH_ALEN;
addr[3] = bssid;
len[3] = ETH_ALEN;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_sta;
len[4] = g_sta_len;
addr[5] = g_ap;
@@ -723,7 +788,7 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
addr[1] = snonce;
addr[2] = bssid;
addr[3] = sta_addr;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_ap;
len[4] = g_ap_len;
addr[5] = g_sta;
@@ -756,10 +821,12 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic)
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic)
{
- const u8 *addr[9];
- size_t len[9];
+ const u8 *addr[10];
+ size_t len[10];
size_t i, num_elem = 0;
u8 zero_mic[24];
size_t mic_len, fte_fixed_len;
@@ -826,6 +893,12 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
num_elem++;
}
+ if (rsnxe) {
+ addr[num_elem] = rsnxe;
+ len[num_elem] = rsnxe_len;
+ num_elem++;
+ }
+
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
#ifdef CONFIG_SHA384
@@ -892,18 +965,20 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
parse->r0kh_id = pos;
parse->r0kh_id_len = len;
break;
-#ifdef CONFIG_IEEE80211W
case FTIE_SUBELEM_IGTK:
parse->igtk = pos;
parse->igtk_len = len;
break;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
case FTIE_SUBELEM_OCI:
parse->oci = pos;
parse->oci_len = len;
break;
#endif /* CONFIG_OCV */
+ case FTIE_SUBELEM_BIGTK:
+ parse->bigtk = pos;
+ parse->bigtk_len = len;
+ break;
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
@@ -958,6 +1033,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
"RSN IE: %d", ret);
return -1;
}
+ parse->rsn_capab = data.capabilities;
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
@@ -968,6 +1044,13 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
update_use_sha384 = 0;
}
break;
+ case WLAN_EID_RSNX:
+ wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
+ if (len < 1)
+ break;
+ parse->rsnxe = pos;
+ parse->rsnxe_len = len;
+ break;
case WLAN_EID_MOBILITY_DOMAIN:
wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
if (len < sizeof(struct rsn_mdie))
@@ -989,9 +1072,11 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie_sha384->mic,
sizeof(ftie_sha384->mic));
+ parse->fte_anonce = ftie_sha384->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie_sha384->anonce,
WPA_NONCE_LEN);
+ parse->fte_snonce = ftie_sha384->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie_sha384->snonce,
WPA_NONCE_LEN);
@@ -1008,8 +1093,10 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
ftie->mic_control, 2);
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie->mic, sizeof(ftie->mic));
+ parse->fte_anonce = ftie->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie->anonce, WPA_NONCE_LEN);
+ parse->fte_snonce = ftie->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
@@ -1046,6 +1133,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
prot_ie_count--;
if (parse->ftie)
prot_ie_count--;
+ if (parse->rsnxe)
+ prot_ie_count--;
if (prot_ie_count < 0) {
wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
"the protected IE count");
@@ -1079,6 +1168,266 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_PASN
+
+/*
+ * pasn_use_sha384 - Should SHA384 be used or SHA256
+ *
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ *
+ * According to IEEE P802.11az/D2.7, 12.12.7, the hash algorithm to use is the
+ * hash algorithm defined for the Base AKM (see Table 9-151 (AKM suite
+ * selectors)). When there is no Base AKM, the hash algorithm is selected based
+ * on the pairwise cipher suite provided in the RSNE by the AP in the second
+ * PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers
+ * 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used.
+ */
+static bool pasn_use_sha384(int akmp, int cipher)
+{
+ return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256)) ||
+ wpa_key_mgmt_sha384(akmp);
+}
+
+
+/**
+ * pasn_pmk_to_ptk - Calculate PASN PTK from PMK, addresses, etc.
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @spa: Suppplicant address
+ * @bssid: AP BSSID
+ * @dhss: Is the shared secret (DHss) derived from the PASN ephemeral key
+ * exchange encoded as an octet string
+ * @dhss_len: The length of dhss in octets
+ * @ptk: Buffer for pairwise transient key
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @kdk_len: the length in octets that should be derived for HTLK. Can be zero.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len)
+{
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
+ u8 *data;
+ size_t data_len, ptk_len;
+ int ret = -1;
+ const char *label = "PASN PTK Derivation";
+
+ if (!pmk || !pmk_len) {
+ wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation");
+ return -1;
+ }
+
+ if (!dhss || !dhss_len) {
+ wpa_printf(MSG_ERROR, "PASN: No DHss set for PTK derivation");
+ return -1;
+ }
+
+ /*
+ * PASN-PTK = KDF(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss)
+ *
+ * KCK = L(PASN-PTK, 0, 256)
+ * TK = L(PASN-PTK, 256, TK_bits)
+ * KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8)
+ */
+ data_len = 2 * ETH_ALEN + dhss_len;
+ data = os_zalloc(data_len);
+ if (!data)
+ return -1;
+
+ os_memcpy(data, spa, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN);
+ os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len);
+
+ ptk->kck_len = WPA_PASN_KCK_LEN;
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
+ ptk->kek_len = 0;
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
+ if (ptk->tk_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "PASN: Unsupported cipher (0x%x) used in PTK derivation",
+ cipher);
+ goto err;
+ }
+
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
+ if (ptk_len > sizeof(tmp))
+ goto err;
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA384");
+
+ if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA256");
+
+ if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR,
+ MAC2STR(spa), MAC2STR(bssid));
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
+
+ os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
+
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
+ ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
+ ptk->kdk, ptk->kdk_len);
+ }
+
+ forced_memzero(tmp, sizeof(tmp));
+ ret = 0;
+err:
+ bin_clear_free(data, data_len);
+ return ret;
+}
+
+
+/*
+ * pasn_mic_len - Returns the MIC length for PASN authentication
+ */
+u8 pasn_mic_len(int akmp, int cipher)
+{
+ if (pasn_use_sha384(akmp, cipher))
+ return 24;
+
+ return 16;
+}
+
+
+/**
+ * pasn_mic - Calculate PASN MIC
+ * @kck: The key confirmation key for the PASN PTKSA
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @addr1: For the 2nd PASN frame supplicant address; for the 3rd frame the
+ * BSSID
+ * @addr2: For the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
+ * address
+ * @data: For calculating the MIC for the 2nd PASN frame, this should hold the
+ * Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN
+ * frame, this should hold the hash of the body of the PASN 1st frame.
+ * @data_len: The length of data
+ * @frame: The body of the PASN frame including the MIC element with the octets
+ * in the MIC field of the MIC element set to 0.
+ * @frame_len: The length of frame
+ * @mic: Buffer to hold the MIC on success. Should be big enough to handle the
+ * maximal MIC length
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic)
+{
+ u8 *buf;
+ u8 hash[SHA384_MAC_LEN];
+ size_t buf_len = 2 * ETH_ALEN + data_len + frame_len;
+ int ret = -1;
+
+ if (!kck) {
+ wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation");
+ return -1;
+ }
+
+ if (!data || !data_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ if (!frame || !frame_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ buf = os_zalloc(buf_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, addr1, ETH_ALEN);
+ os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data", data, data_len);
+ os_memcpy(buf + 2 * ETH_ALEN, data, data_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame", frame, frame_len);
+ os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK", kck, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf", buf, buf_len);
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384");
+
+ if (hmac_sha384(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 24);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 24);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256");
+
+ if (hmac_sha256(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 16);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 16);
+ }
+
+ ret = 0;
+err:
+ bin_clear_free(buf, buf_len);
+ return ret;
+}
+
+
+/**
+ * pasn_auth_frame_hash - Computes a hash of an Authentication frame body
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @data: Pointer to the Authentication frame body
+ * @len: Length of the Authentication frame body
+ * @hash: On return would hold the computed hash. Should be big enough to handle
+ * SHA384.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash)
+{
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-384");
+ return sha384_vector(1, &data, &len, hash);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-256");
+ return sha256_vector(1, &data, &len, hash);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -1087,10 +1436,8 @@ static int rsn_selector_to_bitfield(const u8 *s)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
return WPA_CIPHER_GCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
@@ -1125,12 +1472,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
@@ -1159,6 +1504,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
#endif /* CONFIG_DPP */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
+#ifdef CONFIG_PASN
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PASN)
+ return WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
return 0;
}
@@ -1170,15 +1519,14 @@ int wpa_cipher_valid_group(int cipher)
}
-#ifdef CONFIG_IEEE80211W
int wpa_cipher_valid_mgmt_group(int cipher)
{
- return cipher == WPA_CIPHER_AES_128_CMAC ||
+ return cipher == WPA_CIPHER_GTK_NOT_USED ||
+ cipher == WPA_CIPHER_AES_128_CMAC ||
cipher == WPA_CIPHER_BIP_GMAC_128 ||
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
}
-#endif /* CONFIG_IEEE80211W */
/**
@@ -1203,11 +1551,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
- data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
@@ -1282,13 +1626,11 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
-#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
@@ -1340,7 +1682,6 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
}
}
-#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
@@ -1353,7 +1694,6 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_hexdump(MSG_DEBUG,
@@ -1599,7 +1939,8 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
- os_memset(r0_key_data, 0, sizeof(r0_key_data));
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+ forced_memzero(r0_key_data, sizeof(r0_key_data));
return 0;
}
@@ -1636,6 +1977,7 @@ int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
return 0;
}
@@ -1697,16 +2039,25 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
- u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len, offset;
int use_sha384 = wpa_key_mgmt_sha384(akmp);
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
@@ -1733,8 +2084,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
- ptk->kck2_len + ptk->kek2_len;
+ ptk->kck2_len + ptk->kek2_len + ptk->kdk_len;
#ifdef CONFIG_SHA384
if (use_sha384) {
@@ -1793,6 +2145,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
offset += ptk->kck2_len;
os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
+ offset += ptk->kek2_len;
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
@@ -1802,10 +2156,13 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
if (ptk->kek2_len)
wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
ptk->kek2, ptk->kek2_len);
+ if (ptk->kdk_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KDK", ptk->kdk, ptk->kdk_len);
+
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
- os_memset(tmp, 0, sizeof(tmp));
+ forced_memzero(tmp, sizeof(tmp));
return 0;
}
@@ -1852,11 +2209,9 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
#endif /* CONFIG_FILS || CONFIG_SHA384 */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
} else {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
@@ -1942,10 +2297,12 @@ const char * wpa_cipher_txt(int cipher)
switch (cipher) {
case WPA_CIPHER_NONE:
return "NONE";
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
return "WEP-40";
case WPA_CIPHER_WEP104:
return "WEP-104";
+#endif /* CONFIG_WEP */
case WPA_CIPHER_TKIP:
return "TKIP";
case WPA_CIPHER_CCMP:
@@ -2007,12 +2364,10 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_WPS:
return "WPS";
case WPA_KEY_MGMT_SAE:
@@ -2037,6 +2392,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
return "OWE";
case WPA_KEY_MGMT_DPP:
return "DPP";
+ case WPA_KEY_MGMT_PASN:
+ return "PASN";
default:
return "UNKNOWN";
}
@@ -2083,8 +2440,6 @@ u32 wpa_akm_to_suite(int akm)
return RSN_AUTH_KEY_MGMT_OWE;
if (akm & WPA_KEY_MGMT_DPP)
return RSN_AUTH_KEY_MGMT_DPP;
- if (akm & WPA_KEY_MGMT_OSEN)
- return RSN_AUTH_KEY_MGMT_OSEN;
return 0;
}
@@ -2126,7 +2481,6 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
@@ -2141,11 +2495,10 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
start += 2 + start[1];
}
if (start >= end) {
- wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
@@ -2171,8 +2524,8 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
- wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR,
+ "RSN: Could not parse RSNE in IEs data");
return -1;
}
}
@@ -2203,10 +2556,10 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
* PMKID(s) first before adding the new one.
*/
wpa_printf(MSG_DEBUG,
- "FT: Remove %u old PMKID(s) from RSN IE",
+ "RSN: Remove %u old PMKID(s) from RSNE",
num_pmkid);
after = rpos + 2 + num_pmkid * PMKID_LEN;
- os_memmove(rpos + 2, after, rend - after);
+ os_memmove(rpos + 2, after, end - after);
start[1] -= num_pmkid * PMKID_LEN;
added -= num_pmkid * PMKID_LEN;
}
@@ -2218,14 +2571,13 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
start[1] += PMKID_LEN;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
- "(PMKID inserted)", start, 2 + start[1]);
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+ start, 2 + start[1]);
*ies_len += added;
return 0;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -2278,7 +2630,7 @@ enum wpa_alg wpa_cipher_to_alg(int cipher)
case WPA_CIPHER_TKIP:
return WPA_ALG_TKIP;
case WPA_CIPHER_AES_128_CMAC:
- return WPA_ALG_IGTK;
+ return WPA_ALG_BIP_CMAC_128;
case WPA_CIPHER_BIP_GMAC_128:
return WPA_ALG_BIP_GMAC_128;
case WPA_CIPHER_BIP_GMAC_256:
@@ -2292,11 +2644,18 @@ enum wpa_alg wpa_cipher_to_alg(int cipher)
int wpa_cipher_valid_pairwise(int cipher)
{
+#ifdef CONFIG_NO_TKIP
+ return cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256 ||
+ cipher == WPA_CIPHER_CCMP ||
+ cipher == WPA_CIPHER_GCMP;
+#else /* CONFIG_NO_TKIP */
return cipher == WPA_CIPHER_CCMP_256 ||
cipher == WPA_CIPHER_GCMP_256 ||
cipher == WPA_CIPHER_CCMP ||
cipher == WPA_CIPHER_GCMP ||
cipher == WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
@@ -2449,12 +2808,16 @@ int wpa_parse_cipher(const char *value)
val |= WPA_CIPHER_CCMP;
else if (os_strcmp(start, "GCMP") == 0)
val |= WPA_CIPHER_GCMP;
+#ifndef CONFIG_NO_TKIP
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
else if (os_strcmp(start, "WEP104") == 0)
val |= WPA_CIPHER_WEP104;
else if (os_strcmp(start, "WEP40") == 0)
val |= WPA_CIPHER_WEP40;
+#endif /* CONFIG_WEP */
else if (os_strcmp(start, "NONE") == 0)
val |= WPA_CIPHER_NONE;
else if (os_strcmp(start, "GTK_NOT_USED") == 0)
@@ -2610,3 +2973,760 @@ int fils_domain_name_hash(const char *domain, u8 *hash)
return 0;
}
#endif /* CONFIG_FILS */
+
+
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ */
+static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP,
+ "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, 2 if KDE is not recognized
+ */
+static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+ pos[2 + WPA_SELECTOR_LEN] == 1 &&
+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ ie->wpa_ie = pos;
+ ie->wpa_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+ ie->wpa_ie, ie->wpa_ie_len);
+ return 0;
+ }
+
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
+ ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
+ ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
+ ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
+ ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Transition Disable KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_DPP) {
+ ie->dpp_kde = pos + 2 + RSN_SELECTOR_LEN;
+ ie->dpp_kde_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ return 2;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
+
+ os_memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
+ if (2 + pos[1] > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
+ ret = -1;
+ break;
+ }
+ if (*pos == WLAN_EID_RSN) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+ ie->rsn_ie, ie->rsn_ie_len);
+ } else if (*pos == WLAN_EID_RSNX) {
+ ie->rsnxe = pos;
+ ie->rsnxe_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
+ ie->rsnxe, ie->rsnxe_len);
+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+ ie->mdie = pos;
+ ie->mdie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+ ie->mdie, ie->mdie_len);
+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+ ie->ftie = pos;
+ ie->ftie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+ ie->ftie, ie->ftie_len);
+ } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+ if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+ ie->reassoc_deadline = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+ "in EAPOL-Key",
+ ie->reassoc_deadline, pos[1] + 2);
+ } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+ ie->key_lifetime = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+ "in EAPOL-Key",
+ ie->key_lifetime, pos[1] + 2);
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+ "EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ } else if (*pos == WLAN_EID_LINK_ID) {
+ if (pos[1] >= 18) {
+ ie->lnkid = pos;
+ ie->lnkid_len = pos[1] + 2;
+ }
+ } else if (*pos == WLAN_EID_EXT_CAPAB) {
+ ie->ext_capab = pos;
+ ie->ext_capab_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_SUPP_RATES) {
+ ie->supp_rates = pos;
+ ie->supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+ ie->ext_supp_rates = pos;
+ ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
+ ie->ht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+ {
+ ie->vht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + IEEE80211_HE_CAPAB_MIN_LEN &&
+ pos[2] == WLAN_EID_EXT_HE_CAPABILITIES) {
+ ie->he_capabilities = pos + 3;
+ ie->he_capab_len = pos[1] - 1;
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+ ret = wpa_parse_generic(pos, ie);
+ if (ret == 1) {
+ /* end mark found */
+ ret = 0;
+ break;
+ }
+
+ if (ret == 2) {
+ /* not a known KDE */
+ wpa_parse_vendor_specific(pos, end, ie);
+ }
+
+ ret = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Unrecognized EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ }
+
+ return ret;
+}
+
+
+#ifdef CONFIG_PASN
+
+/*
+ * wpa_pasn_build_auth_header - Add the MAC header and initialize Authentication
+ * frame for PASN
+ *
+ * @buf: Buffer in which the header will be added
+ * @bssid: The BSSID of the AP
+ * @src: Source address
+ * @dst: Destination address
+ * @trans_seq: Authentication transaction sequence number
+ * @status: Authentication status
+ */
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status)
+{
+ struct ieee80211_mgmt *auth;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add authentication header. trans_seq=%u",
+ trans_seq);
+
+ auth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.auth.variable));
+
+ auth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ os_memcpy(auth->da, dst, ETH_ALEN);
+ os_memcpy(auth->sa, src, ETH_ALEN);
+ os_memcpy(auth->bssid, bssid, ETH_ALEN);
+ auth->seq_ctrl = 0;
+
+ auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_PASN);
+ auth->u.auth.auth_transaction = host_to_le16(trans_seq);
+ auth->u.auth.status_code = host_to_le16(status);
+}
+
+
+/*
+ * wpa_pasn_add_rsne - Add an RSNE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pmkid: Optional PMKID. Can be NULL.
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ */
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
+{
+ struct rsn_ie_hdr *hdr;
+ u32 suite;
+ u16 capab;
+ u8 *pos;
+ u8 rsne_len;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add RSNE");
+
+ rsne_len = sizeof(*hdr) + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + (pmkid ? PMKID_LEN : 0);
+
+ if (wpabuf_tailroom(buf) < rsne_len)
+ return -1;
+ hdr = wpabuf_put(buf, rsne_len);
+ hdr->elem_id = WLAN_EID_RSN;
+ hdr->len = rsne_len - 2;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ /* Group addressed data is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the pairwise cipher */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, cipher);
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the AKM suite */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+
+ switch (akmp) {
+ case WPA_KEY_MGMT_PASN:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ break;
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ break;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ break;
+ case WPA_KEY_MGMT_FILS_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+ break;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+ break;
+#endif /* CONFIG_IEEE80211R */
+ default:
+ wpa_printf(MSG_ERROR, "PASN: Invalid AKMP=0x%x", akmp);
+ return -1;
+ }
+ pos += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities: PASN mandates both MFP capable and required */
+ capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ WPA_PUT_LE16(pos, capab);
+ pos += 2;
+
+ if (pmkid) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding PMKID");
+
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ os_memcpy(pos, pmkid, PMKID_LEN);
+ pos += PMKID_LEN;
+ } else {
+ WPA_PUT_LE16(pos, 0);
+ pos += 2;
+ }
+
+ /* Group addressed management is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_add_parameter_ie - Add PASN Parameters IE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pasn_group: Finite Cyclic Group ID for PASN authentication
+ * @wrapped_data_format: Format of the data in the Wrapped Data IE
+ * @pubkey: A buffer holding the local public key. Can be NULL
+ * @compressed: In case pubkey is included, indicates if the public key is
+ * compressed (only x coordinate is included) or not (both x and y
+ * coordinates are included)
+ * @comeback: A buffer holding the comeback token. Can be NULL
+ * @after: If comeback is set, defined the comeback time in seconds. -1 to not
+ * include the Comeback After field (frames from non-AP STA).
+ */
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ const struct wpabuf *pubkey, bool compressed,
+ const struct wpabuf *comeback, int after)
+{
+ struct pasn_parameter_ie *params;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add PASN Parameters element");
+
+ params = wpabuf_put(buf, sizeof(*params));
+
+ params->id = WLAN_EID_EXTENSION;
+ params->len = sizeof(*params) - 2;
+ params->id_ext = WLAN_EID_EXT_PASN_PARAMS;
+ params->control = 0;
+ params->wrapped_data_format = wrapped_data_format;
+
+ if (comeback) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding comeback data");
+
+ /*
+ * 2 octets for the 'after' field + 1 octet for the length +
+ * actual cookie data
+ */
+ if (after >= 0)
+ params->len += 2;
+ params->len += 1 + wpabuf_len(comeback);
+ params->control |= WPA_PASN_CTRL_COMEBACK_INFO_PRESENT;
+
+ if (after >= 0)
+ wpabuf_put_le16(buf, after);
+ wpabuf_put_u8(buf, wpabuf_len(comeback));
+ wpabuf_put_buf(buf, comeback);
+ }
+
+ if (pubkey) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Adding public key and group ID %u",
+ pasn_group);
+
+ /*
+ * 2 octets for the finite cyclic group + 2 octets public key
+ * length + 1 octet for the compressed/uncompressed indication +
+ * the actual key.
+ */
+ params->len += 2 + 1 + 1 + wpabuf_len(pubkey);
+ params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
+
+ wpabuf_put_le16(buf, pasn_group);
+
+ /*
+ * The first octet indicates whether the public key is
+ * compressed, as defined in RFC 5480 section 2.2.
+ */
+ wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1);
+ wpabuf_put_u8(buf, compressed ? WPA_PASN_PUBKEY_COMPRESSED_0 :
+ WPA_PASN_PUBKEY_UNCOMPRESSED);
+
+ wpabuf_put_buf(buf, pubkey);
+ }
+}
+
+/*
+ * wpa_pasn_add_wrapped_data - Add a Wrapped Data IE to PASN Authentication
+ * frame. If needed, the Wrapped Data IE would be fragmented.
+ *
+ * @buf: Buffer in which the IE will be added
+ * @wrapped_data_buf: Buffer holding the wrapped data
+ */
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf)
+{
+ const u8 *data;
+ size_t data_len;
+ u8 len;
+
+ if (!wrapped_data_buf)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add wrapped data");
+
+ data = wpabuf_head_u8(wrapped_data_buf);
+ data_len = wpabuf_len(wrapped_data_buf);
+
+ /* nothing to add */
+ if (!data_len)
+ return 0;
+
+ if (data_len <= 254)
+ len = 1 + data_len;
+ else
+ len = 255;
+
+ if (wpabuf_tailroom(buf) < 3 + data_len)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_data(buf, data, len - 1);
+
+ data += len - 1;
+ data_len -= len - 1;
+
+ while (data_len) {
+ if (wpabuf_tailroom(buf) < 1 + data_len)
+ return -1;
+ wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
+ len = data_len > 255 ? 255 : data_len;
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_data(buf, data, len);
+ data += len;
+ data_len -= len;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_validate_rsne - Validate PSAN specific data of RSNE
+ * @data: Parsed representation of an RSNE
+ * Returns -1 for invalid data; otherwise 0
+ */
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
+{
+ u16 capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+
+ if (data->proto != WPA_PROTO_RSN)
+ return -1;
+
+ if ((data->capabilities & capab) != capab) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid RSNE capabilities");
+ return -1;
+ }
+
+ if (!data->has_group || data->group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher");
+ return -1;
+ }
+
+ if (!data->has_pairwise || !data->pairwise_cipher ||
+ (data->pairwise_cipher & (data->pairwise_cipher - 1))) {
+ wpa_printf(MSG_DEBUG, "PASN: No valid pairwise suite");
+ return -1;
+ }
+
+ switch (data->key_mgmt) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ /* fall through */
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ /* fall through */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /* fall through */
+#endif /* CONFIG_IEEE80211R */
+ case WPA_KEY_MGMT_PASN:
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "PASN: invalid key_mgmt: 0x%0x",
+ data->key_mgmt);
+ return -1;
+ }
+
+ if (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher");
+ return -1;
+ }
+
+ if (data->num_pmkid > 1) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid number of PMKIDs");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_parse_parameter_ie - Validates PASN Parameters IE
+ * @data: Pointer to the PASN Parameters IE (starting with the EID).
+ * @len: Length of the data in the PASN Parameters IE
+ * @from_ap: Whether this was received from an AP
+ * @pasn_params: On successful return would hold the parsed PASN parameters.
+ * Returns: -1 for invalid data; otherwise 0
+ *
+ * Note: On successful return, the pointers in &pasn_params point to the data in
+ * the IE and are not locally allocated (so they should not be freed etc.).
+ */
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params)
+{
+ struct pasn_parameter_ie *params = (struct pasn_parameter_ie *) data;
+ const u8 *pos = (const u8 *) (params + 1);
+
+ if (!pasn_params) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid params");
+ return -1;
+ }
+
+ if (!params || ((size_t) (params->len + 2) < sizeof(*params)) ||
+ len < sizeof(*params) || params->len + 2 != len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid parameters IE. len=(%u, %u)",
+ params ? params->len : 0, len);
+ return -1;
+ }
+
+ os_memset(pasn_params, 0, sizeof(*pasn_params));
+
+ switch (params->wrapped_data_format) {
+ case WPA_PASN_WRAPPED_DATA_NO:
+ case WPA_PASN_WRAPPED_DATA_SAE:
+ case WPA_PASN_WRAPPED_DATA_FILS_SK:
+ case WPA_PASN_WRAPPED_DATA_FT:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "PASN: Invalid wrapped data format");
+ return -1;
+ }
+
+ pasn_params->wrapped_data_format = params->wrapped_data_format;
+
+ len -= sizeof(*params);
+
+ if (params->control & WPA_PASN_CTRL_COMEBACK_INFO_PRESENT) {
+ if (from_ap) {
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: Truncated Comeback After");
+ return -1;
+ }
+ pasn_params->after = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ }
+
+ if (len < 1 || len < 1 + *pos) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: comeback len");
+ return -1;
+ }
+
+ pasn_params->comeback_len = *pos++;
+ len--;
+ pasn_params->comeback = pos;
+ len -= pasn_params->comeback_len;
+ pos += pasn_params->comeback_len;
+ }
+
+ if (params->control & WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT) {
+ if (len < 3 || len < 3 + pos[2]) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: group and key");
+ return -1;
+ }
+
+ pasn_params->group = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ pasn_params->pubkey_len = *pos++;
+ len--;
+ pasn_params->pubkey = pos;
+ len -= pasn_params->pubkey_len;
+ pos += pasn_params->pubkey_len;
+ }
+
+ if (len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE. Bytes left=%u", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab)
+{
+ size_t flen;
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return; /* no supported extended RSN capabilities */
+ if (wpabuf_tailroom(buf) < 2 + flen)
+ return;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ wpabuf_put_u8(buf, WLAN_EID_RSNX);
+ wpabuf_put_u8(buf, flen);
+ wpabuf_put_u8(buf, capab & 0x00ff);
+ capab >>= 8;
+ if (capab)
+ wpabuf_put_u8(buf, capab);
+}
+
+#endif /* CONFIG_PASN */
diff --git a/contrib/wpa/src/common/wpa_common.h b/contrib/wpa/src/common/wpa_common.h
index e83d6887a1cd..a1ff895659cb 100644
--- a/contrib/wpa/src/common/wpa_common.h
+++ b/contrib/wpa/src/common/wpa_common.h
@@ -19,9 +19,21 @@
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define WPA_PASN_PMK_LEN 32
+#define WPA_PASN_MAX_MIC_LEN 24
+#define WPA_MAX_RSNXE_LEN 4
#define OWE_DH_GROUP 19
+#ifdef CONFIG_NO_TKIP
+#define WPA_ALLOWED_PAIRWISE_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_NONE | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
+#define WPA_ALLOWED_GROUP_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
+WPA_CIPHER_GTK_NOT_USED)
+#else /* CONFIG_NO_TKIP */
#define WPA_ALLOWED_PAIRWISE_CIPHERS \
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
@@ -29,6 +41,7 @@ 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)
+#endif /* CONFIG_NO_TKIP */
#define WPA_ALLOWED_GROUP_MGMT_CIPHERS \
(WPA_CIPHER_AES_128_CMAC | WPA_CIPHER_BIP_GMAC_128 | WPA_CIPHER_BIP_GMAC_256 | \
WPA_CIPHER_BIP_CMAC_256)
@@ -68,6 +81,9 @@ WPA_CIPHER_BIP_CMAC_256)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+
+#define RSN_AUTH_KEY_MGMT_PASN RSN_SELECTOR(0x00, 0x0f, 0xac, 21)
+
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_AUTH_KEY_MGMT_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x02)
@@ -104,16 +120,17 @@ WPA_CIPHER_BIP_CMAC_256)
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
+#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
+#define WFA_KEY_DATA_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x21)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@@ -130,10 +147,10 @@ WPA_CIPHER_BIP_CMAC_256)
#pragma pack(push, 1)
#endif /* _MSC_VER */
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
-#endif /* CONFIG_IEEE80211W */
+#define WPA_BIGTK_LEN 16
+#define WPA_BIGTK_MAX_LEN 32
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -200,8 +217,11 @@ struct wpa_eapol_key {
#define WPA_KCK_MAX_LEN 32
#define WPA_KEK_MAX_LEN 64
#define WPA_TK_MAX_LEN 32
+#define WPA_KDK_MAX_LEN 32
#define FILS_ICK_MAX_LEN 48
#define FILS_FT_MAX_LEN 48
+#define WPA_PASN_KCK_LEN 32
+#define WPA_PASN_MIC_MAX_LEN 24
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -213,11 +233,13 @@ struct wpa_ptk {
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
+ u8 kdk[WPA_KDK_MAX_LEN]; /* Key Derivation Key */
size_t kck_len;
size_t kek_len;
size_t tk_len;
size_t kck2_len;
size_t kek2_len;
+ size_t kdk_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -226,12 +248,15 @@ struct wpa_gtk {
size_t gtk_len;
};
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk {
u8 igtk[WPA_IGTK_MAX_LEN];
size_t igtk_len;
};
-#endif /* CONFIG_IEEE80211W */
+
+struct wpa_bigtk {
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+};
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
@@ -291,14 +316,19 @@ struct rsn_error_kde {
be16 error_type;
} STRUCT_PACKED;
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
+
+#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6)
+struct wpa_bigtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -329,6 +359,7 @@ struct rsn_ftie_sha384 {
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
#define FTIE_SUBELEM_OCI 5
+#define FTIE_SUBELEM_BIGTK 6
struct rsn_rdie {
u8 id;
@@ -336,6 +367,16 @@ struct rsn_rdie {
le16 status_code;
} STRUCT_PACKED;
+/* WFA Transition Disable KDE (using OUI_WFA) */
+/* Transition Disable Bitmap bits */
+#define TRANSITION_DISABLE_WPA3_PERSONAL BIT(0)
+#define TRANSITION_DISABLE_SAE_PK BIT(1)
+#define TRANSITION_DISABLE_WPA3_ENTERPRISE BIT(2)
+#define TRANSITION_DISABLE_ENHANCED_OPEN BIT(3)
+
+/* DPP KDE Flags */
+#define DPP_KDE_PFS_ALLOWED BIT(0)
+#define DPP_KDE_PFS_REQUIRED BIT(1)
#ifdef _MSC_VER
#pragma pack(pop)
@@ -348,7 +389,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len);
+ const u8 *z, size_t z_len, size_t kdk_len);
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
@@ -358,7 +399,7 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len);
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len);
int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *g_sta, size_t g_sta_len,
@@ -372,7 +413,9 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic);
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic);
int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
@@ -387,7 +430,8 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -451,13 +495,18 @@ struct wpa_ft_ies {
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
+ const u8 *fte_anonce;
+ const u8 *fte_snonce;
const u8 *rsn;
size_t rsn_len;
+ u16 rsn_capab;
const u8 *rsn_pmkid;
const u8 *tie;
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+ const u8 *bigtk;
+ size_t bigtk_len;
#ifdef CONFIG_OCV
const u8 *oci;
size_t oci_len;
@@ -466,11 +515,108 @@ struct wpa_ft_ies {
size_t ric_len;
int key_mgmt;
int pairwise_cipher;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
+};
+
+/* IEEE P802.11az/D2.6 - 9.4.2.303 PASN Parameters element */
+#define WPA_PASN_CTRL_COMEBACK_INFO_PRESENT BIT(0)
+#define WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT BIT(1)
+
+#define WPA_PASN_WRAPPED_DATA_NO 0
+#define WPA_PASN_WRAPPED_DATA_FT 1
+#define WPA_PASN_WRAPPED_DATA_FILS_SK 2
+#define WPA_PASN_WRAPPED_DATA_SAE 3
+
+struct pasn_parameter_ie {
+ u8 id;
+ u8 len;
+ u8 id_ext;
+ u8 control; /* WPA_PASN_CTRL_* */
+ u8 wrapped_data_format; /* WPA_PASN_WRAPPED_DATA_* */
+} STRUCT_PACKED;
+
+struct wpa_pasn_params_data {
+ u8 wrapped_data_format;
+ u16 after;
+ u8 comeback_len;
+ const u8 *comeback;
+ u16 group;
+ u8 pubkey_len;
+ const u8 *pubkey;
};
+/* See RFC 5480 section 2.2 */
+#define WPA_PASN_PUBKEY_COMPRESSED_0 0x02
+#define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
+#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
+
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *key_id;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+ const u8 *igtk;
+ size_t igtk_len;
+ const u8 *bigtk;
+ size_t bigtk_len;
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+ const u8 *transition_disable;
+ size_t transition_disable_len;
+ const u8 *dpp_kde;
+ size_t dpp_kde_len;
+ const u8 *oci;
+ size_t oci_len;
+ const u8 *osen;
+ size_t osen_len;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
+ const u8 *reassoc_deadline;
+ const u8 *key_lifetime;
+ const u8 *lnkid;
+ size_t lnkid_len;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ const u8 *ext_supp_rates;
+ size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ const u8 *vht_capabilities;
+ const u8 *he_capabilities;
+ size_t he_capab_len;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
+static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie)
+{
+ return wpa_parse_kde_ies(buf, len, ie);
+}
+
+
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
enum wpa_alg wpa_cipher_to_alg(int cipher);
@@ -491,4 +637,41 @@ int wpa_use_cmac(int akmp);
int wpa_use_aes_key_wrap(int akmp);
int fils_domain_name_hash(const char *domain, u8 *hash);
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len);
+
+u8 pasn_mic_len(int akmp, int cipher);
+
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic);
+
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash);
+
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status);
+
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
+ int akmp, int cipher);
+
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ const struct wpabuf *pubkey, bool compressed,
+ const struct wpabuf *comeback, int after);
+
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf);
+
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data);
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params);
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
+
#endif /* WPA_COMMON_H */
diff --git a/contrib/wpa/src/common/wpa_ctrl.c b/contrib/wpa/src/common/wpa_ctrl.c
index c9890a0e4905..40a979531b53 100644
--- a/contrib/wpa/src/common/wpa_ctrl.c
+++ b/contrib/wpa/src/common/wpa_ctrl.c
@@ -266,7 +266,6 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl)
void wpa_ctrl_cleanup(void)
{
DIR *dir;
- struct dirent entry;
struct dirent *result;
size_t dirnamelen;
size_t maxcopy;
@@ -284,8 +283,8 @@ void wpa_ctrl_cleanup(void)
}
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
- while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ while ((result = readdir(dir)) != NULL) {
+ if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
unlink(pathname);
}
closedir(dir);
diff --git a/contrib/wpa/src/common/wpa_ctrl.h b/contrib/wpa/src/common/wpa_ctrl.h
index b24ae63e59ea..126a7892c8a8 100644
--- a/contrib/wpa/src/common/wpa_ctrl.h
+++ b/contrib/wpa/src/common/wpa_ctrl.h
@@ -95,6 +95,12 @@ extern "C" {
/** SAE authentication failed due to unknown password identifier */
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
+/** Unprotected Beacon frame dropped */
+#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
+/** Decision made to do a within-ESS roam */
+#define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
+/** Decision made to skip a within-ESS roam */
+#define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM "
/** IP subnet status change notification
*
@@ -120,6 +126,8 @@ extern "C" {
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** Frequency ranges that the driver recommends to avoid */
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
+/** Result of MSCS setup */
+#define WPA_EVENT_MSCS_RESULT "CTRL-EVENT-MSCS-RESULT "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
@@ -168,15 +176,22 @@ extern "C" {
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
+#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
+#define DPP_EVENT_PP_KEY "DPP-PP-KEY "
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
+#define DPP_EVENT_SERVER_NAME "DPP-SERVER-NAME "
+#define DPP_EVENT_CERTBAG "DPP-CERTBAG "
+#define DPP_EVENT_CACERT "DPP-CACERT "
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
+#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
#define DPP_EVENT_RX "DPP-RX "
#define DPP_EVENT_TX "DPP-TX "
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
@@ -184,6 +199,11 @@ extern "C" {
#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
#define DPP_EVENT_INTRO "DPP-INTRO "
#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
+#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
+#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
+#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
+#define DPP_EVENT_CSR "DPP-CSR "
+#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -251,7 +271,7 @@ extern "C" {
#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
#define INTERWORKING_AP "INTERWORKING-AP "
-#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
+#define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
@@ -299,6 +319,8 @@ extern "C" {
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
+#define WPS_EVENT_PIN_ACTIVE "WPS-PIN-ACTIVE "
+#define WPS_EVENT_CANCEL "WPS-CANCEL "
#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 "
@@ -375,6 +397,23 @@ extern "C" {
#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+/* Transition mode disabled indication - followed by bitmap */
+#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+
+/* OCV validation failure; parameters: addr=<src addr>
+ * frame=<saqueryreq/saqueryresp> error=<error string> */
+#define OCV_FAILURE "OCV-FAILURE "
+
+/* Event triggered for received management frame */
+#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
+
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
+/* PASN authentication status */
+#define PASN_AUTH_STATUS "PASN-AUTH-STATUS "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/contrib/wpa/src/crypto/Makefile b/contrib/wpa/src/crypto/Makefile
new file mode 100644
index 000000000000..ce0997091de1
--- /dev/null
+++ b/contrib/wpa/src/crypto/Makefile
@@ -0,0 +1,60 @@
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+#CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
+CFLAGS += -DCONFIG_SHA384
+CFLAGS += -DCONFIG_HMAC_SHA384_KDF
+CFLAGS += -DCONFIG_INTERNAL_SHA384
+
+LIB_OBJS= \
+ aes-cbc.o \
+ aes-ccm.o \
+ aes-ctr.o \
+ aes-eax.o \
+ aes-encblock.o \
+ aes-gcm.o \
+ aes-internal.o \
+ aes-internal-dec.o \
+ aes-internal-enc.o \
+ aes-omac1.o \
+ aes-siv.o \
+ aes-unwrap.o \
+ aes-wrap.o \
+ des-internal.o \
+ dh_group5.o \
+ dh_groups.o \
+ md4-internal.o \
+ md5.o \
+ md5-internal.o \
+ milenage.o \
+ ms_funcs.o \
+ rc4.o \
+ sha1.o \
+ sha1-internal.o \
+ sha1-pbkdf2.o \
+ sha1-prf.o \
+ sha1-tlsprf.o \
+ sha1-tprf.o \
+ sha256.o \
+ sha256-prf.o \
+ sha256-tlsprf.o \
+ sha256-internal.o \
+ sha384.o \
+ sha384-prf.o \
+ sha384-internal.o \
+ sha512.o \
+ sha512-prf.o \
+ sha512-internal.o
+
+LIB_OBJS += crypto_internal.o
+LIB_OBJS += crypto_internal-cipher.o
+LIB_OBJS += crypto_internal-modexp.o
+LIB_OBJS += crypto_internal-rsa.o
+LIB_OBJS += tls_internal.o
+LIB_OBJS += fips_prf_internal.o
+ifndef TEST_FUZZ
+LIB_OBJS += random.o
+endif
+
+include ../lib.rules
diff --git a/contrib/wpa/src/crypto/crypto.h b/contrib/wpa/src/crypto/crypto.h
index 15f8ad04cea4..7d2ebd61caea 100644
--- a/contrib/wpa/src/crypto/crypto.h
+++ b/contrib/wpa/src/crypto/crypto.h
@@ -485,7 +485,7 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
/**
- * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * crypto_get_random - Generate cryptographically strong pseudo-random bytes
* @buf: Buffer for data
* @len: Number of bytes to generate
* Returns: 0 on success, -1 on failure
@@ -519,6 +519,13 @@ struct crypto_bignum * crypto_bignum_init(void);
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value (uint)
+ * @val: Value to set
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val);
+
+/**
* crypto_bignum_deinit - Free bignum
* @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
* @clear: Whether to clear the value from memory
@@ -613,6 +620,19 @@ int crypto_bignum_div(const struct crypto_bignum *a,
struct crypto_bignum *c);
/**
+ * crypto_bignum_addmod - d = a + b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a + b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
* crypto_bignum_mulmod - d = a * b (mod c)
* @a: Bignum
* @b: Bignum
@@ -626,6 +646,17 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
struct crypto_bignum *d);
/**
+ * crypto_bignum_sqrmod - c = a^2 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a^2 % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
* crypto_bignum_rshift - r = a >> n
* @a: Bignum
* @n: Number of bits
@@ -731,6 +762,9 @@ const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
*/
const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
+
/**
* struct crypto_ec_point - Elliptic curve point
*
@@ -882,5 +916,18 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y);
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len);
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
+
+struct crypto_ec_key;
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len);
+void crypto_ec_key_deinit(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len);
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len);
+int crypto_ec_key_group(struct crypto_ec_key *key);
#endif /* CRYPTO_H */
diff --git a/contrib/wpa/src/crypto/crypto_module_tests.c b/contrib/wpa/src/crypto/crypto_module_tests.c
index 1cc73d8ec16e..fafb688b45f6 100644
--- a/contrib/wpa/src/crypto/crypto_module_tests.c
+++ b/contrib/wpa/src/crypto/crypto_module_tests.c
@@ -744,6 +744,155 @@ static int test_key_wrap(void)
}
+static int test_aes_ctr(void)
+{
+ int res = 0;
+
+#if defined(CONFIG_MESH) || defined(CONFIG_PSK)
+ /* CTR-AES*.Encrypt test vectors from NIST SP 800-38a */
+ const u8 key128[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ const u8 counter128[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain128[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher128[] = {
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+ 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+ 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+ 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+ 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+ };
+ const u8 key192[] = {
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+ 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b
+ };
+ const u8 counter192[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain192[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher192[] = {
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2,
+ 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef,
+ 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70,
+ 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58,
+ 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50
+ };
+ const u8 key256[] = {
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+ 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+ 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
+ };
+ const u8 counter256[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain256[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher256[] = {
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5,
+ 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a,
+ 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c,
+ 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6,
+ 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6
+ };
+ size_t len;
+ u8 *tmp;
+
+ wpa_printf(MSG_DEBUG, "CTR-AES128.Encrypt");
+ len = sizeof(plain128);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain128, len);
+ if (aes_ctr_encrypt(key128, sizeof(key128), counter128, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher128, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES128.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES192.Encrypt");
+ len = sizeof(plain192);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain192, len);
+ if (aes_ctr_encrypt(key192, sizeof(key192), counter192, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher192, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES192.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES256.Encrypt");
+ len = sizeof(plain256);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain256, len);
+ if (aes_ctr_encrypt(key256, sizeof(key256), counter256, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher256, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES256.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+#endif
+
+ return res;
+}
+
+
static int test_md5(void)
{
#ifndef CONFIG_FIPS
@@ -2154,6 +2303,7 @@ int crypto_module_tests(void)
test_cbc() ||
test_ecb() ||
test_key_wrap() ||
+ test_aes_ctr() ||
test_md5() ||
test_sha1() ||
test_sha256() ||
diff --git a/contrib/wpa/src/crypto/crypto_openssl.c b/contrib/wpa/src/crypto/crypto_openssl.c
index bab33a537293..a4b1083bb4c1 100644
--- a/contrib/wpa/src/crypto/crypto_openssl.c
+++ b/contrib/wpa/src/crypto/crypto_openssl.c
@@ -21,6 +21,7 @@
#endif /* CONFIG_OPENSSL_CMAC */
#ifdef CONFIG_ECC
#include <openssl/ec.h>
+#include <openssl/x509.h>
#endif /* CONFIG_ECC */
#include "common.h"
@@ -79,6 +80,16 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
bin_clear_free(ctx, sizeof(*ctx));
}
+
+#ifdef CONFIG_ECC
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+#endif /* CONFIG_ECC */
+
#endif /* OpenSSL version < 1.1.0 */
static BIGNUM * get_group5_prime(void)
@@ -1283,6 +1294,24 @@ struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_new();
+ if (!bn)
+ return NULL;
+ if (BN_set_word(bn, val) != 1) {
+ BN_free(bn);
+ return NULL;
+ }
+ return (struct crypto_bignum *) bn;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (clear)
@@ -1449,6 +1478,28 @@ int crypto_bignum_div(const struct crypto_bignum *a,
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_add((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *c,
@@ -1472,6 +1523,27 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_sqr((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1682,6 +1754,18 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
if (clear)
@@ -2095,4 +2179,170 @@ void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
}
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
+
+struct crypto_ec_key {
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+};
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->eckey = d2i_ECPrivateKey(NULL, &der, der_len);
+ if (!key->eckey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_conv_form(key->eckey, POINT_CONVERSION_COMPRESSED);
+
+ key->pkey = EVP_PKEY_new();
+ if (!key->pkey || EVP_PKEY_assign_EC_KEY(key->pkey, key->eckey) != 1) {
+ EC_KEY_free(key->eckey);
+ key->eckey = NULL;
+ goto fail;
+ }
+
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->pkey = d2i_PUBKEY(NULL, &der, der_len);
+ if (!key->pkey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ key->eckey = EVP_PKEY_get0_EC_KEY(key->pkey);
+ if (!key->eckey)
+ goto fail;
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ if (key) {
+ EVP_PKEY_free(key->pkey);
+ os_free(key);
+ }
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ struct wpabuf *buf;
+
+ der_len = i2d_PUBKEY(key->pkey, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ return buf;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len)
+{
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *sig_der;
+ size_t sig_len;
+
+ sig_len = EVP_PKEY_size(key->pkey);
+ sig_der = wpabuf_alloc(sig_len);
+ if (!sig_der)
+ return NULL;
+
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx ||
+ EVP_PKEY_sign_init(pkctx) <= 0 ||
+ EVP_PKEY_sign(pkctx, wpabuf_put(sig_der, 0), &sig_len,
+ data, len) <= 0) {
+ wpabuf_free(sig_der);
+ sig_der = NULL;
+ } else {
+ wpabuf_put(sig_der, sig_len);
+ }
+
+ EVP_PKEY_CTX_free(pkctx);
+ return sig_der;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len)
+{
+ EVP_PKEY_CTX *pkctx;
+ int ret;
+
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx || EVP_PKEY_verify_init(pkctx) <= 0) {
+ EVP_PKEY_CTX_free(pkctx);
+ return -1;
+ }
+
+ ret = EVP_PKEY_verify(pkctx, sig, sig_len, data, len);
+ EVP_PKEY_CTX_free(pkctx);
+ if (ret == 1)
+ return 1; /* signature ok */
+ if (ret == 0)
+ return 0; /* incorrect signature */
+ return -1;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+ const EC_GROUP *group;
+ int nid;
+
+ group = EC_KEY_get0_group(key->eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ switch (nid) {
+ case NID_X9_62_prime256v1:
+ return 19;
+ case NID_secp384r1:
+ return 20;
+ case NID_secp521r1:
+ return 21;
+ }
+ return -1;
+}
+
#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/crypto_wolfssl.c b/contrib/wpa/src/crypto/crypto_wolfssl.c
index 4cedab4367cd..2e4bf8962b55 100644
--- a/contrib/wpa/src/crypto/crypto_wolfssl.c
+++ b/contrib/wpa/src/crypto/crypto_wolfssl.c
@@ -1042,6 +1042,26 @@ struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_set_int(a, val) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (!n)
@@ -1084,19 +1104,21 @@ int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
{
int ret = 0;
WC_RNG rng;
+ size_t len;
+ u8 *buf;
if (TEST_FAIL())
return -1;
if (wc_InitRng(&rng) != 0)
return -1;
- if (mp_rand_prime((mp_int *) r,
- (mp_count_bits((mp_int *) m) + 7) / 8 * 2,
- &rng, NULL) != 0)
- ret = -1;
- if (ret == 0 &&
+ len = (mp_count_bits((mp_int *) m) + 7) / 8;
+ buf = os_malloc(len);
+ if (!buf || wc_RNG_GenerateBlock(&rng, buf, len) != 0 ||
+ mp_read_unsigned_bin((mp_int *) r, buf, len) != MP_OKAY ||
mp_mod((mp_int *) r, (mp_int *) m, (mp_int *) r) != 0)
ret = -1;
wc_FreeRng(&rng);
+ bin_clear_free(buf, len);
return ret;
}
@@ -1151,7 +1173,7 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
if (TEST_FAIL())
return -1;
- return mp_add((mp_int *) a, (mp_int *) b,
+ return mp_sub((mp_int *) a, (mp_int *) b,
(mp_int *) r) == MP_OKAY ? 0 : -1;
}
@@ -1168,6 +1190,19 @@ int crypto_bignum_div(const struct crypto_bignum *a,
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_addmod((mp_int *) a, (mp_int *) b, (mp_int *) c,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *m,
@@ -1181,6 +1216,18 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_sqrmod((mp_int *) a, (mp_int *) b,
+ (mp_int *) c) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1386,6 +1433,18 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
ecc_point *point = (ecc_point *) p;
@@ -1777,4 +1836,10 @@ fail:
goto done;
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/sha256.c b/contrib/wpa/src/crypto/sha256.c
index b55e976f37b0..17af964ad049 100644
--- a/contrib/wpa/src/crypto/sha256.c
+++ b/contrib/wpa/src/crypto/sha256.c
@@ -28,10 +28,10 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/contrib/wpa/src/crypto/sha384-tlsprf.c b/contrib/wpa/src/crypto/sha384-tlsprf.c
new file mode 100644
index 000000000000..9ff96ac2c7b2
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384-tlsprf.c
@@ -0,0 +1,71 @@
+/*
+ * TLS PRF P_SHA384
+ * Copyright (c) 2011-2019, 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"
+
+
+/**
+ * tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
+ */
+int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+ size_t clen;
+ u8 A[SHA384_MAC_LEN];
+ u8 P[SHA384_MAC_LEN];
+ size_t pos;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = A;
+ len[0] = SHA384_MAC_LEN;
+ addr[1] = (unsigned char *) label;
+ len[1] = os_strlen(label);
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ /*
+ * RFC 5246, Chapter 5
+ * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+ * PRF(secret, label, seed) = P_SHA384(secret, label + seed)
+ */
+
+ if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+ return -1;
+
+ pos = 0;
+ while (pos < outlen) {
+ if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
+ 0 ||
+ hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
+ return -1;
+
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, P, clen);
+ pos += clen;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha384.c b/contrib/wpa/src/crypto/sha384.c
index ee136ce99b7e..fd84b82b1afa 100644
--- a/contrib/wpa/src/crypto/sha384.c
+++ b/contrib/wpa/src/crypto/sha384.c
@@ -28,10 +28,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[48];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/contrib/wpa/src/crypto/sha384.h b/contrib/wpa/src/crypto/sha384.h
index 2241425385c3..d946907c675d 100644
--- a/contrib/wpa/src/crypto/sha384.h
+++ b/contrib/wpa/src/crypto/sha384.h
@@ -20,6 +20,9 @@ int sha384_prf(const u8 *key, size_t key_len, const char *label,
int 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);
+int tls_prf_sha384(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/contrib/wpa/src/crypto/sha512.c b/contrib/wpa/src/crypto/sha512.c
index 66311c373920..f60a57672346 100644
--- a/contrib/wpa/src/crypto/sha512.c
+++ b/contrib/wpa/src/crypto/sha512.c
@@ -28,10 +28,10 @@ int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[64];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/contrib/wpa/src/crypto/tls.h b/contrib/wpa/src/crypto/tls.h
index c8b1a824ed54..09fb73b1ae24 100644
--- a/contrib/wpa/src/crypto/tls.h
+++ b/contrib/wpa/src/crypto/tls.h
@@ -670,4 +670,18 @@ int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
*/
u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
+/**
+ * tls_connection_get_peer_subject - Get peer subject
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Peer subject or %NULL if not authenticated or not available
+ */
+const char * tls_connection_get_peer_subject(struct tls_connection *conn);
+
+/**
+ * tls_connection_get_own_cert_used - Was own certificate used
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: true if own certificate was used during authentication
+ */
+bool tls_connection_get_own_cert_used(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/contrib/wpa/src/crypto/tls_openssl.c b/contrib/wpa/src/crypto/tls_openssl.c
index 07d38e47b917..345a35ee16f4 100644
--- a/contrib/wpa/src/crypto/tls_openssl.c
+++ b/contrib/wpa/src/crypto/tls_openssl.c
@@ -265,6 +265,7 @@ struct tls_connection {
X509 *peer_cert;
X509 *peer_issuer;
X509 *peer_issuer_issuer;
+ char *peer_subject; /* peer subject info for authenticated peer */
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
@@ -1044,6 +1045,8 @@ void * tls_init(const struct tls_config *conf)
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
#ifdef SSL_MODE_NO_AUTO_CHAIN
/* Number of deployed use cases assume the default OpenSSL behavior of
* auto chaining the local certificate is in use. BoringSSL removed this
@@ -1629,6 +1632,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->domain_match);
os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
+ os_free(conn->peer_subject);
os_free(conn);
}
@@ -2186,8 +2190,11 @@ static int openssl_cert_tod(X509 *cert)
continue;
wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
- tod = 1;
+ tod = 1; /* TOD-STRICT */
+ else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
+ tod = 2; /* TOD-TOFU */
}
+ sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
return tod;
}
@@ -2294,6 +2301,38 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
}
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print(out, cert);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+ }
+ os_free(txt);
+ }
+
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -2314,6 +2353,8 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
+ os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
+ debug_print_cert(err_cert, buf);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
@@ -2542,6 +2583,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (depth == 0 && preverify_ok) {
+ os_free(conn->peer_subject);
+ conn->peer_subject = os_strdup(buf);
+ }
+
return preverify_ok;
}
@@ -2951,16 +2997,12 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
/* Explicit request to enable TLS versions even if needing to
* override systemwide policies. */
- if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ if (flags & TLS_CONN_ENABLE_TLSv1_0)
version = TLS1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
- if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
- version = TLS1_1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
- if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
- TLS_CONN_DISABLE_TLSv1_1)))
- version = TLS1_2_VERSION;
- }
+ else if (flags & TLS_CONN_ENABLE_TLSv1_1)
+ version = TLS1_1_VERSION;
+ else if (flags & TLS_CONN_ENABLE_TLSv1_2)
+ version = TLS1_2_VERSION;
if (!version) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Invalid TLS version configuration");
@@ -2974,6 +3016,18 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
}
}
#endif /* >= 1.1.0 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ if ((flags & (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
+ SSL_get_security_level(ssl) >= 2) {
+ /*
+ * Need to drop to security level 1 to allow TLS versions older
+ * than 1.2 to be used when explicitly enabled in configuration.
+ */
+ SSL_set_security_level(conn->ssl, 1);
+ }
+#endif
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
@@ -3143,7 +3197,11 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
- if (verify_peer) {
+ if (verify_peer == 2) {
+ conn->ca_cert_verify = 1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
+ } else if (verify_peer) {
conn->ca_cert_verify = 1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
@@ -3204,8 +3262,36 @@ static int tls_connection_client_cert(struct tls_connection *conn,
"OK");
return 0;
} else if (client_cert_blob) {
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_ASN1 failed");
+#else
+ BIO *bio;
+ X509 *x509;
+
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_ASN1 failed");
+ bio = BIO_new(BIO_s_mem());
+ if (!bio)
+ return -1;
+ BIO_write(bio, client_cert_blob, client_cert_blob_len);
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
+ X509_free(x509);
+ BIO_free(bio);
+ return -1;
+ }
+ X509_free(x509);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found PEM encoded certificate from blob");
+ while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Added an additional certificate into the chain");
+ SSL_add0_chain_cert(conn->ssl, x509);
+ }
+ BIO_free(bio);
+ return 0;
+#endif
}
if (client_cert == NULL)
@@ -3712,6 +3798,17 @@ static int tls_connection_private_key(struct tls_data *data,
break;
}
+#ifndef OPENSSL_NO_EC
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
+ ok = 1;
+ break;
+ }
+#endif /* OPENSSL_NO_EC */
+
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
@@ -4011,6 +4108,7 @@ static int openssl_get_keyblock_size(SSL *ssl)
int cipher, digest;
const EVP_CIPHER *c;
const EVP_MD *h;
+ int mac_key_len, enc_key_len, fixed_iv_len;
ssl_cipher = SSL_get_current_cipher(ssl);
if (!ssl_cipher)
@@ -4021,17 +4119,33 @@ static int openssl_get_keyblock_size(SSL *ssl)
cipher, digest);
if (cipher < 0 || digest < 0)
return -1;
+ if (cipher == NID_undef) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: no cipher in use?!");
+ return -1;
+ }
c = EVP_get_cipherbynid(cipher);
- h = EVP_get_digestbynid(digest);
- if (!c || !h)
+ if (!c)
return -1;
+ enc_key_len = EVP_CIPHER_key_length(c);
+ if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
+ EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
+ fixed_iv_len = 4; /* only part of IV from PRF */
+ else
+ fixed_iv_len = EVP_CIPHER_iv_length(c);
+ if (digest == NID_undef) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: no digest in use (e.g., AEAD)");
+ mac_key_len = 0;
+ } else {
+ h = EVP_get_digestbynid(digest);
+ if (!h)
+ return -1;
+ mac_key_len = EVP_MD_size(h);
+ }
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));
+ "OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
+ mac_key_len, enc_key_len, fixed_iv_len);
+ return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
#endif
}
#endif /* OPENSSL_NEED_EAP_FAST_PRF */
@@ -4431,10 +4545,18 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
return NULL;
res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
if (res < 0) {
- tls_show_errors(MSG_INFO, __func__,
- "Decryption failed - SSL_read");
- wpabuf_free(buf);
- return NULL;
+ int err = SSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: SSL_connect - want more data");
+ res = 0;
+ } else {
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
}
wpabuf_put(buf, res);
@@ -4656,41 +4778,6 @@ static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
}
-static void debug_print_cert(X509 *cert, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
-
- if (wpa_debug_level > MSG_DEBUG)
- return;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- X509_print(out, cert);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (!txt) {
- BIO_free(out);
- return;
- }
-
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
- }
- os_free(txt);
-
- BIO_free(out);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
@@ -4890,6 +4977,76 @@ static int ocsp_status_cb(SSL *s, void *arg)
#endif /* HAVE_OCSP */
+static size_t max_str_len(const char **lines)
+{
+ const char **p;
+ size_t max_len = 0;
+
+ for (p = lines; *p; p++) {
+ size_t len = os_strlen(*p);
+
+ if (len > max_len)
+ max_len = len;
+ }
+
+ return max_len;
+}
+
+
+static int match_lines_in_file(const char *path, const char **lines)
+{
+ FILE *f;
+ char *buf;
+ size_t bufsize;
+ int found = 0, is_linestart = 1;
+
+ bufsize = max_str_len(lines) + sizeof("\r\n");
+ buf = os_malloc(bufsize);
+ if (!buf)
+ return 0;
+
+ f = fopen(path, "r");
+ if (!f) {
+ os_free(buf);
+ return 0;
+ }
+
+ while (!found && fgets(buf, bufsize, f)) {
+ int is_lineend;
+ size_t len;
+ const char **p;
+
+ len = strcspn(buf, "\r\n");
+ is_lineend = buf[len] != '\0';
+ buf[len] = '\0';
+
+ if (is_linestart && is_lineend) {
+ for (p = lines; !found && *p; p++)
+ found = os_strcmp(buf, *p) == 0;
+ }
+ is_linestart = is_lineend;
+ }
+
+ fclose(f);
+ bin_clear_free(buf, bufsize);
+
+ return found;
+}
+
+
+static int is_tpm2_key(const char *path)
+{
+ /* Check both new and old format of TPM2 PEM guard tag */
+ static const char *tpm2_tags[] = {
+ "-----BEGIN TSS2 PRIVATE KEY-----",
+ "-----BEGIN TSS2 KEY BLOB-----",
+ NULL
+ };
+
+ return match_lines_in_file(path, tpm2_tags);
+}
+
+
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
@@ -4942,6 +5099,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (can_pkcs11 == 2 && !engine_id)
engine_id = "pkcs11";
+ /* If private_key points to a TPM2-wrapped key, automatically enable
+ * tpm2 engine and use it to unwrap the key. */
+ if (params->private_key &&
+ (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
+ is_tpm2_key(params->private_key)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
+ params->private_key);
+ key_id = key_id ? key_id : params->private_key;
+ engine_id = engine_id ? engine_id : "tpm2";
+ }
+
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
@@ -4973,7 +5141,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
if (engine_id) {
- wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
+ engine_id);
ret = tls_engine_init(conn, engine_id, params->pin,
key_id, cert_id, ca_cert_id);
if (ret)
@@ -5164,6 +5333,9 @@ static void openssl_debug_dump_certificate(int i, X509 *cert)
ASN1_INTEGER *ser;
char serial_num[128];
+ if (!cert)
+ return;
+
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
ser = X509_get_serialNumber(cert);
@@ -5548,3 +5720,19 @@ u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
return SSL_CIPHER_get_id(cipher) & 0xFFFF;
#endif
}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+ if (conn)
+ return conn->peer_subject;
+ return NULL;
+}
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+ if (conn)
+ return SSL_get_certificate(conn->ssl) != NULL;
+ return false;
+}
diff --git a/contrib/wpa/src/crypto/tls_wolfssl.c b/contrib/wpa/src/crypto/tls_wolfssl.c
index d222d142767d..cf482bfc3a16 100644
--- a/contrib/wpa/src/crypto/tls_wolfssl.c
+++ b/contrib/wpa/src/crypto/tls_wolfssl.c
@@ -19,6 +19,7 @@
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/openssl/x509v3.h>
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#define HAVE_AESGCM
@@ -468,7 +469,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
if (client_cert_blob) {
if (wolfSSL_use_certificate_chain_buffer_format(
conn->ssl, client_cert_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER blob failed");
return -1;
@@ -478,13 +479,13 @@ static int tls_connection_client_cert(struct tls_connection *conn,
}
if (client_cert) {
- if (wolfSSL_use_certificate_chain_file(conn->ssl,
- client_cert) < 0) {
+ if (wolfSSL_use_certificate_chain_file(
+ conn->ssl, client_cert) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert PEM file failed");
if (wolfSSL_use_certificate_chain_file_format(
conn->ssl, client_cert,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER file failed");
return -1;
@@ -533,7 +534,7 @@ static int tls_connection_private_key(void *tls_ctx,
if (private_key_blob) {
if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
private_key_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) <= 0) {
wpa_printf(MSG_INFO,
"SSL: use private DER blob failed");
} else {
@@ -544,11 +545,11 @@ static int tls_connection_private_key(void *tls_ctx,
if (!ok && private_key) {
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) < 0) {
+ SSL_FILETYPE_PEM) <= 0) {
wpa_printf(MSG_INFO,
"SSL: use private key PEM file failed");
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) < 0)
+ SSL_FILETYPE_ASN1) <= 0)
{
wpa_printf(MSG_INFO,
"SSL: use private key DER file failed");
@@ -576,7 +577,7 @@ static int tls_connection_private_key(void *tls_ctx,
static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
const char *value, size_t len)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int found = 0;
int i;
@@ -585,14 +586,15 @@ static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
gen = wolfSSL_sk_value(ext, i);
- if (gen->type != type)
+ if (!gen || gen->type != type)
continue;
- if (os_strlen((char *) gen->obj) == len &&
- os_memcmp(value, gen->obj, len) == 0)
+ if ((size_t) wolfSSL_ASN1_STRING_length(gen->d.ia5) == len &&
+ os_memcmp(value, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ len) == 0)
found++;
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
return found;
}
@@ -676,7 +678,7 @@ static int domain_suffix_match(const char *val, size_t len, const char *match,
static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
size_t match_len, int full)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
int j;
@@ -690,21 +692,23 @@ static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
gen = wolfSSL_sk_value(ext, j);
- if (gen->type != ASN_DNS_TYPE)
+ if (!gen || gen->type != ASN_DNS_TYPE)
continue;
dns_name++;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
- gen->obj, os_strlen((char *)gen->obj));
- if (domain_suffix_match((const char *) gen->obj,
- os_strlen((char *) gen->obj), match,
- match_len, full) == 1) {
+ wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ if (domain_suffix_match(
+ (const char *) wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5), match,
+ match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
wolfSSL_sk_ASN1_OBJECT_free(ext);
return 1;
}
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -858,7 +862,7 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
struct tls_context *context = conn->context;
char *alt_subject[TLS_MAX_ALT_SUBJECT];
int alt, num_alt_subject = 0;
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
#ifdef CONFIG_SHA256
@@ -899,12 +903,14 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
break;
gen = wolfSSL_sk_value((void *) ext, i);
- if (gen->type != GEN_EMAIL &&
- gen->type != GEN_DNS &&
- gen->type != GEN_URI)
+ if (!gen ||
+ (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI))
continue;
- pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ pos = os_malloc(10 + wolfSSL_ASN1_STRING_length(gen->d.ia5) +
+ 1);
if (!pos)
break;
alt_subject[num_alt_subject++] = pos;
@@ -924,11 +930,12 @@ static void wolfssl_tls_cert_event(struct tls_connection *conn,
break;
}
- os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
- pos += os_strlen((char *)gen->obj);
+ os_memcpy(pos, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ pos += wolfSSL_ASN1_STRING_length(gen->d.ia5);
*pos = '\0';
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
for (alt = 0; alt < num_alt_subject; alt++)
ev.peer_cert.altsubject[alt] = alt_subject[alt];
@@ -1741,7 +1748,7 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx,
if (!conn)
return NULL;
- wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+ wpa_printf(MSG_DEBUG, "SSL: encrypt: %zu bytes", wpabuf_len(in_data));
wolfssl_reset_out_data(&conn->output);
@@ -1792,7 +1799,7 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
}
wpabuf_put(buf, res);
- wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+ wpa_printf(MSG_DEBUG, "SSL: decrypt: %zu bytes", wpabuf_len(buf));
return buf;
}
diff --git a/contrib/wpa/src/drivers/Makefile b/contrib/wpa/src/drivers/Makefile
new file mode 100644
index 000000000000..5721154014ec
--- /dev/null
+++ b/contrib/wpa/src/drivers/Makefile
@@ -0,0 +1,9 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f build.wpa_supplicant build.hostapd
+
+install:
+ @echo Nothing to be made.
diff --git a/contrib/wpa/src/drivers/android_drv.h b/contrib/wpa/src/drivers/android_drv.h
new file mode 100644
index 000000000000..31d94408a92f
--- /dev/null
+++ b/contrib/wpa/src/drivers/android_drv.h
@@ -0,0 +1,56 @@
+/*
+ * Android driver interface
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE 248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS 4
+
+#define WEXT_PNOSETUP_HEADER "PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE 9
+#define WEXT_PNO_TLV_PREFIX 'S'
+#define WEXT_PNO_TLV_VERSION '1'
+#define WEXT_PNO_TLV_SUBVERSION '2'
+#define WEXT_PNO_TLV_RESERVED '0'
+#define WEXT_PNO_VERSION_SIZE 4
+#define WEXT_PNO_AMOUNT 16
+#define WEXT_PNO_SSID_SECTION 'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE 2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION 'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH 2
+#define WEXT_PNO_SCAN_INTERVAL 30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE (1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION 'R'
+#define WEXT_PNO_REPEAT_LENGTH 1
+#define WEXT_PNO_REPEAT 4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE (1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION 'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH 1
+#define WEXT_PNO_MAX_REPEAT 3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE (1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+ (WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+ + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+ + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
diff --git a/contrib/wpa/src/drivers/driver.h b/contrib/wpa/src/drivers/driver.h
index 2a8459ae3f2d..804ac6806f61 100644
--- a/contrib/wpa/src/drivers/driver.h
+++ b/contrib/wpa/src/drivers/driver.h
@@ -182,6 +182,7 @@ struct hostapd_channel_data {
struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
};
+#define HE_MAC_CAPAB_0 0
#define HE_MAX_MAC_CAPAB_SIZE 6
#define HE_MAX_PHY_CAPAB_SIZE 11
#define HE_MAX_MCS_CAPAB_SIZE 12
@@ -196,6 +197,7 @@ struct he_capabilities {
u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
+ u16 he_6ghz_capa;
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -213,6 +215,24 @@ enum ieee80211_op_mode {
};
/**
+ * struct ieee80211_edmg_config - EDMG configuration
+ *
+ * This structure describes most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration
+ *
+ * @channels: Bitmap that indicates the 2.16 GHz channel(s)
+ * that are allowed to be used for transmissions.
+ * Bit 0 indicates channel 1, bit 1 indicates channel 2, etc.
+ * Set to 0 to indicate EDMG not supported.
+ * @bw_config: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations
+ */
+struct ieee80211_edmg_config {
+ u8 channels;
+ enum edmg_bw_config bw_config;
+};
+
+/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
struct hostapd_hw_modes {
@@ -272,6 +292,12 @@ struct hostapd_hw_modes {
* he_capab - HE (IEEE 802.11ax) capabilities
*/
struct he_capabilities he_capab[IEEE80211_MODE_NUM];
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
@@ -493,7 +519,7 @@ struct wpa_driver_scan_params {
* mac_addr - MAC address used with randomization. The address cannot be
* a multicast one, i.e., bit 0 of byte 0 should not be set.
*/
- const u8 *mac_addr;
+ u8 *mac_addr;
/**
* mac_addr_mask - MAC address mask used with randomization.
@@ -619,6 +645,12 @@ struct wpa_driver_scan_params {
*/
unsigned int oce_scan:1;
+ /**
+ * p2p_include_6ghz - Include 6 GHz channels for P2P full scan
+ *
+ */
+ unsigned int p2p_include_6ghz:1;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -744,6 +776,12 @@ struct hostapd_freq_params {
* bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
*/
int bandwidth;
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
/**
@@ -1065,6 +1103,13 @@ struct wpa_driver_associate_params {
const struct ieee80211_vht_capabilities *vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE for this connection
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* req_key_mgmt_offload - Request key management offload for connection
*
@@ -1150,6 +1195,14 @@ struct wpa_driver_associate_params {
* fils_erp_rrk_len - Length of fils_erp_rrk in bytes
*/
size_t fils_erp_rrk_len;
+
+ /**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
};
enum hide_ssid {
@@ -1217,14 +1270,14 @@ struct wpa_driver_ap_params {
*
* This parameter can be used to set a specific Beacon frame data rate
* for the BSS. The interpretation of this value depends on the
- * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
- * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
- * Beacon frame data rate is used.
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS,
+ * HE: HE-MCS). If beacon_rate == 0 and rate_type == 0
+ * (BEACON_RATE_LEGACY), the default Beacon frame data rate is used.
*/
unsigned int beacon_rate;
/**
- * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT/HE)
*/
enum beacon_rate_type rate_type;
@@ -1372,14 +1425,6 @@ struct wpa_driver_ap_params {
u8 p2p_go_ctwindow;
/**
- * smps_mode - SMPS mode
- *
- * SMPS mode to be used by the AP, specified as the relevant bits of
- * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
- */
- unsigned int smps_mode;
-
- /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
@@ -1442,6 +1487,101 @@ struct wpa_driver_ap_params {
* type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
*/
const struct wpabuf *civic;
+
+ /**
+ * he_spr_ctrl - Spatial Reuse control field of SPR element
+ */
+ u8 he_spr_ctrl;
+
+ /**
+ * he_spr_non_srg_obss_pd_max_offset - Non-SRG Maximum TX power offset
+ */
+ u8 he_spr_non_srg_obss_pd_max_offset;
+
+ /**
+ * he_spr_srg_obss_pd_min_offset - Minimum TX power offset
+ */
+ u8 he_spr_srg_obss_pd_min_offset;
+
+ /**
+ * he_spr_srg_obss_pd_max_offset - Maximum TX power offset
+ */
+ u8 he_spr_srg_obss_pd_max_offset;
+
+ /**
+ * he_spr_bss_color_bitmap - BSS color values used by members of the
+ * SRG.
+ */
+ u8 he_spr_bss_color_bitmap[8];
+
+ /**
+ * he_spr_partial_bssid_bitmap - Partial BSSID values used by members
+ * of the SRG.
+ */
+ u8 he_spr_partial_bssid_bitmap[8];
+
+ /**
+ * he_bss_color - Whether the BSS Color is disabled
+ */
+ int he_bss_color_disabled;
+
+ /**
+ * he_bss_color_partial - The BSS Color AID equation
+ */
+ int he_bss_color_partial;
+
+ /**
+ * he_bss_color - The BSS Color of the AP
+ */
+ int he_bss_color;
+
+ /**
+ * twt_responder - Whether Target Wait Time responder is enabled
+ */
+ int twt_responder;
+
+ /**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
+ * FILS Discovery frame minimum interval in TUs
+ */
+ u32 fd_min_int;
+
+ /**
+ * FILS Discovery frame maximum interval in TUs (0 = FD frame disabled)
+ */
+ u32 fd_max_int;
+
+ /**
+ * FILS Discovery frame template data
+ */
+ u8 *fd_frame_tmpl;
+
+ /**
+ * FILS Discovery frame template length
+ */
+ size_t fd_frame_tmpl_len;
+
+ /**
+ * Unsolicited broadcast Probe Response interval in TUs
+ */
+ unsigned int unsol_bcast_probe_resp_interval;
+
+ /**
+ * Unsolicited broadcast Probe Response template data
+ */
+ u8 *unsol_bcast_probe_resp_tmpl;
+
+ /**
+ * Unsolicited broadcast Probe Response template length
+ */
+ size_t unsol_bcast_probe_resp_tmpl_len;
};
struct wpa_driver_mesh_bss_params {
@@ -1477,6 +1617,189 @@ struct wpa_driver_mesh_join_params {
#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
unsigned int flags;
+ bool handle_dfs;
+};
+
+struct wpa_driver_set_key_params {
+ /**
+ * ifname - Interface name (for multi-SSID/VLAN support) */
+ const char *ifname;
+
+ /**
+ * alg - Encryption algorithm
+ *
+ * (%WPA_ALG_NONE, %WPA_ALG_WEP, %WPA_ALG_TKIP, %WPA_ALG_CCMP,
+ * %WPA_ALG_BIP_AES_CMAC_128, %WPA_ALG_GCMP, %WPA_ALG_GCMP_256,
+ * %WPA_ALG_CCMP_256, %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
+ * %WPA_ALG_BIP_CMAC_256);
+ * %WPA_ALG_NONE clears the key. */
+ enum wpa_alg alg;
+
+ /**
+ * addr - Address of the peer STA
+ *
+ * (BSSID of the current AP when setting pairwise key in station mode),
+ * ff:ff:ff:ff:ff:ff for broadcast keys, %NULL for default keys that
+ * are used both for broadcast and unicast; when clearing keys, %NULL
+ * is used to indicate that both the broadcast-only and default key of
+ * the specified key index is to be cleared */
+ const u8 *addr;
+
+ /**
+ * key_idx - Key index
+ *
+ * (0..3), usually 0 for unicast keys; 4..5 for IGTK; 6..7 for BIGTK */
+ int key_idx;
+
+ /**
+ * set_tx - Configure this key as the default Tx key
+ *
+ * Only used when driver does not support separate unicast/individual
+ * key */
+ int set_tx;
+
+ /**
+ * seq - Sequence number/packet number
+ *
+ * seq_len octets, the next packet number to be used for in replay
+ * protection; configured for Rx keys (in most cases, this is only used
+ * with broadcast keys and set to zero for unicast keys); %NULL if not
+ * set */
+ const u8 *seq;
+
+ /**
+ * seq_len - Length of the seq, depends on the algorithm
+ *
+ * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets */
+ size_t seq_len;
+
+ /**
+ * key - Key buffer
+ *
+ * TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key */
+ const u8 *key;
+
+ /**
+ * key_len - Length of the key buffer in octets
+ *
+ * WEP: 5 or 13, TKIP: 32, CCMP/GCMP: 16, IGTK: 16 */
+ size_t key_len;
+
+ /**
+ * vlan_id - VLAN index (0..4095) for VLAN offload cases */
+ int vlan_id;
+
+ /**
+ * key_flag - Additional key flags
+ *
+ * %KEY_FLAG_MODIFY
+ * Set when an already installed key must be updated.
+ * So far the only use-case is changing RX/TX status for
+ * pairwise keys. Must not be set when deleting a key.
+ * %KEY_FLAG_DEFAULT
+ * Set when the key is also a default key. Must not be set when
+ * deleting a key.
+ * %KEY_FLAG_RX
+ * The key is valid for RX. Must not be set when deleting a key.
+ * %KEY_FLAG_TX
+ * The key is valid for TX. Must not be set when deleting a key.
+ * %KEY_FLAG_GROUP
+ * The key is a broadcast or group key.
+ * %KEY_FLAG_PAIRWISE
+ * The key is a pairwise key.
+ * %KEY_FLAG_PMK
+ * The key is a Pairwise Master Key (PMK).
+ *
+ * Valid and pre-defined combinations are:
+ * %KEY_FLAG_GROUP_RX_TX
+ * WEP key not to be installed as default key.
+ * %KEY_FLAG_GROUP_RX_TX_DEFAULT
+ * Default WEP or WPA-NONE key.
+ * %KEY_FLAG_GROUP_RX
+ * GTK key valid for RX only.
+ * %KEY_FLAG_GROUP_TX_DEFAULT
+ * GTK key valid for TX only, immediately taking over TX.
+ * %KEY_FLAG_PAIRWISE_RX_TX
+ * Pairwise key immediately becoming the active pairwise key.
+ * %KEY_FLAG_PAIRWISE_RX
+ * Pairwise key not yet valid for TX. (Only usable when Extended
+ * Key ID is supported by the driver.)
+ * %KEY_FLAG_PAIRWISE_RX_TX_MODIFY
+ * Enable TX for a pairwise key installed with
+ * KEY_FLAG_PAIRWISE_RX.
+ *
+ * Not a valid standalone key type but pre-defined to be combined
+ * with other key_flags:
+ * %KEY_FLAG_RX_TX
+ * RX/TX key. */
+ enum key_flag key_flag;
+};
+
+enum wpa_driver_if_type {
+ /**
+ * WPA_IF_STATION - Station mode interface
+ */
+ WPA_IF_STATION,
+
+ /**
+ * WPA_IF_AP_VLAN - AP mode VLAN interface
+ *
+ * This interface shares its address and Beacon frame with the main
+ * BSS.
+ */
+ WPA_IF_AP_VLAN,
+
+ /**
+ * WPA_IF_AP_BSS - AP mode BSS interface
+ *
+ * This interface has its own address and Beacon frame.
+ */
+ WPA_IF_AP_BSS,
+
+ /**
+ * WPA_IF_P2P_GO - P2P Group Owner
+ */
+ WPA_IF_P2P_GO,
+
+ /**
+ * WPA_IF_P2P_CLIENT - P2P Client
+ */
+ WPA_IF_P2P_CLIENT,
+
+ /**
+ * WPA_IF_P2P_GROUP - P2P Group interface (will become either
+ * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
+ */
+ WPA_IF_P2P_GROUP,
+
+ /**
+ * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+ * abstracted P2P Device function in the driver
+ */
+ WPA_IF_P2P_DEVICE,
+
+ /*
+ * 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,
+
+ /*
+ * WPA_IF_NAN - NAN Device
+ */
+ WPA_IF_NAN,
+
+ /* keep last */
+ WPA_IF_MAX
};
/**
@@ -1500,8 +1823,16 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
+#define WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256 0x00020000
+#define WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256 0x00040000
+#define WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE 0x00080000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE 0x00100000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384 0x00200000
+#define WPA_DRIVER_CAPA_KEY_MGMT_CCKM 0x00400000
+#define WPA_DRIVER_CAPA_KEY_MGMT_OSEN 0x00800000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
+ unsigned int key_mgmt_iftype[WPA_IF_MAX];
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
#define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002
@@ -1532,7 +1863,7 @@ struct wpa_driver_capa {
/** Driver takes care of all DFS operations */
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
- * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+ * struct wpa_driver_ops::set_key using key_flag = KEY_FLAG_PMK */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
@@ -1659,15 +1990,46 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
/** Driver support 4-way handshake offload for WPA-Personal */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
+/** Driver supports a separate control port TX for EAPOL frames */
+#define WPA_DRIVER_FLAGS_CONTROL_PORT 0x0400000000000000ULL
+/** Driver supports VLAN offload */
+#define WPA_DRIVER_FLAGS_VLAN_OFFLOAD 0x0800000000000000ULL
+/** Driver supports UPDATE_FT_IES command */
+#define WPA_DRIVER_FLAGS_UPDATE_FT_IES 0x1000000000000000ULL
+/** Driver can correctly rekey PTKs without Extended Key ID */
+#define WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS 0x2000000000000000ULL
+/** Driver supports Beacon protection */
+#define WPA_DRIVER_FLAGS_BEACON_PROTECTION 0x4000000000000000ULL
+/** Driver supports Extended Key ID */
+#define WPA_DRIVER_FLAGS_EXTENDED_KEY_ID 0x8000000000000000ULL
u64 flags;
+/** Driver supports a separate control port RX for EAPOL frames */
+#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
+/** Driver supports TX status reports for EAPOL frames through control port */
+#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
+/** Driver supports secure LTF */
+#define WPA_DRIVER_FLAGS2_SEC_LTF 0x0000000000000004ULL
+/** Driver supports secure RTT measurement exchange */
+#define WPA_DRIVER_FLAGS2_SEC_RTT 0x0000000000000008ULL
+/**
+ * Driver supports protection of range negotiation and measurement management
+ * frames
+ */
+#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG 0x0000000000000010ULL
+/** Driver supports Beacon frame TX rate configuration (HE rates) */
+#define WPA_DRIVER_FLAGS2_BEACON_RATE_HE 0x0000000000000020ULL
+/** Driver supports Beacon protection only in client mode */
+#define WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT 0x0000000000000040ULL
+/** Driver supports Operating Channel Validation */
+#define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
+/** Driver expects user space implementation of SME in AP mode */
+#define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
+ u64 flags2;
+
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
(drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
-#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
-#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
- unsigned int smps_modes;
-
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
@@ -1827,6 +2189,7 @@ struct hostapd_sta_add_params {
u8 vht_opmode;
const struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
u32 flags; /* bitmask of WPA_STA_* flags */
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
@@ -1854,65 +2217,6 @@ struct hostapd_acl_params {
struct mac_address mac_acl[0];
};
-enum wpa_driver_if_type {
- /**
- * WPA_IF_STATION - Station mode interface
- */
- WPA_IF_STATION,
-
- /**
- * WPA_IF_AP_VLAN - AP mode VLAN interface
- *
- * This interface shares its address and Beacon frame with the main
- * BSS.
- */
- WPA_IF_AP_VLAN,
-
- /**
- * WPA_IF_AP_BSS - AP mode BSS interface
- *
- * This interface has its own address and Beacon frame.
- */
- WPA_IF_AP_BSS,
-
- /**
- * WPA_IF_P2P_GO - P2P Group Owner
- */
- WPA_IF_P2P_GO,
-
- /**
- * WPA_IF_P2P_CLIENT - P2P Client
- */
- WPA_IF_P2P_CLIENT,
-
- /**
- * WPA_IF_P2P_GROUP - P2P Group interface (will become either
- * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
- */
- WPA_IF_P2P_GROUP,
-
- /**
- * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
- * abstracted P2P Device function in the driver
- */
- WPA_IF_P2P_DEVICE,
-
- /*
- * 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 {
void *global_priv;
const u8 *bssid;
@@ -2094,6 +2398,7 @@ enum tdls_peer_capability {
TDLS_PEER_HT = BIT(0),
TDLS_PEER_VHT = BIT(1),
TDLS_PEER_WMM = BIT(2),
+ TDLS_PEER_HE = BIT(3),
};
/* valid info in the wmm_params struct */
@@ -2115,9 +2420,9 @@ struct wmm_params {
#ifdef CONFIG_MACSEC
struct macsec_init_params {
- Boolean always_include_sci;
- Boolean use_es;
- Boolean use_scb;
+ bool always_include_sci;
+ bool use_es;
+ bool use_scb;
};
#endif /* CONFIG_MACSEC */
@@ -2147,10 +2452,11 @@ struct drv_acs_params {
/* Configured ACS channel width */
u16 ch_width;
- /* ACS channel list info */
- unsigned int ch_list_len;
- const u8 *ch_list;
+ /* ACS frequency list info */
const int *freq_list;
+
+ /* Indicates whether EDMG is enabled */
+ int edmg_enabled;
};
struct wpa_bss_trans_info {
@@ -2176,6 +2482,8 @@ struct wpa_pmkid_params {
const u8 *pmkid;
const u8 *pmk;
size_t pmk_len;
+ u32 pmk_lifetime;
+ u8 pmk_reauth_threshold;
};
/* Mask used to specify which connection parameters have to be updated */
@@ -2217,6 +2525,13 @@ struct external_auth {
const u8 *pmkid;
};
+/* enum nested_attr - Used to specify if subcommand uses nested attributes */
+enum nested_attr {
+ NESTED_ATTR_NOT_USED = 0,
+ NESTED_ATTR_USED = 1,
+ NESTED_ATTR_UNSPECIFIED = 2,
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
@@ -2262,35 +2577,8 @@ struct wpa_driver_ops {
/**
* set_key - Configure encryption key
- * @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
- * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
- * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
- * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
- * %WPA_ALG_BIP_CMAC_256);
- * %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA (BSSID of the current AP when setting
- * pairwise key in station mode), ff:ff:ff:ff:ff:ff for
- * broadcast keys, %NULL for default keys that are used both for
- * broadcast and unicast; when clearing keys, %NULL is used to
- * indicate that both the broadcast-only and default key of the
- * specified key index is to be cleared
- * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
- * IGTK
- * @set_tx: configure this key as the default Tx key (only used when
- * driver does not support separate unicast/individual key
- * @seq: sequence number/packet number, seq_len octets, the next
- * packet number to be used for in replay protection; configured
- * for Rx keys (in most cases, this is only used with broadcast
- * keys and set to zero for unicast keys); %NULL if not set
- * @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
- * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- * 8-byte Rx Mic Key
- * @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
- *
+ * @params: Key parameters
* Returns: 0 on success, -1 on failure
*
* Configure the given key for the kernel driver. If the driver
@@ -2311,10 +2599,7 @@ struct wpa_driver_ops {
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
- int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ int (*set_key)(void *priv, struct wpa_driver_set_key_params *params);
/**
* init - Initialize driver interface
@@ -2566,11 +2851,15 @@ struct wpa_driver_ops {
* driver decide
* @csa_offs: Array of CSA offsets or %NULL
* @csa_offs_len: Number of elements in csa_offs
+ * @no_encrypt: Do not encrypt frame even if appropriate key exists
+ * (used only for testing purposes)
+ * @wait: Time to wait off-channel for a response (in ms), or zero
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
int noack, unsigned int freq, const u16 *csa_offs,
- size_t csa_offs_len);
+ size_t csa_offs_len, int no_encrypt,
+ unsigned int wait);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2825,6 +3114,33 @@ struct wpa_driver_ops {
const u8 *addr);
/**
+ * tx_control_port - Send a frame over the 802.1X controlled port
+ * @priv: Private driver interface data
+ * @dest: Destination MAC address
+ * @proto: Ethertype in host byte order
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ * @no_encrypt: Do not encrypt frame
+ *
+ * Returns 0 on success, else an error
+ *
+ * This is like a normal Ethernet send except that the driver is aware
+ * (by other means than the Ethertype) that this frame is special,
+ * and more importantly it gains an ordering between the transmission of
+ * the frame and other driver management operations such as key
+ * installations. This can be used to work around known limitations in
+ * IEEE 802.11 protocols such as race conditions between rekeying 4-way
+ * handshake message 4/4 and a PTK being overwritten.
+ *
+ * This function is only used for a given interface if the driver
+ * instance reports WPA_DRIVER_FLAGS_CONTROL_PORT capability. Otherwise,
+ * API users will fall back to sending the frame via a normal socket.
+ */
+ int (*tx_control_port)(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt);
+
+ /**
* hapd_send_eapol - Send an EAPOL packet (AP only)
* @priv: private driver interface data
* @addr: Destination MAC address
@@ -3070,19 +3386,6 @@ struct wpa_driver_ops {
int (*commit)(void *priv);
/**
- * send_ether - Send an ethernet packet (AP only)
- * @priv: private driver interface data
- * @dst: Destination MAC address
- * @src: Source MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Length of the EAPOL packet in octets
- * Returns: 0 on success, -1 on failure
- */
- int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
- const u8 *data, size_t data_len);
-
- /**
* set_radius_acl_auth - Notification of RADIUS ACL change
* @priv: Private driver interface data
* @mac: MAC address of the station
@@ -3305,20 +3608,6 @@ struct wpa_driver_ops {
int (*signal_monitor)(void *priv, int threshold, int hysteresis);
/**
- * send_frame - Send IEEE 802.11 frame (testing use only)
- * @priv: Private driver interface data
- * @data: IEEE 802.11 frame with IEEE 802.11 header
- * @data_len: Size of the frame
- * @encrypt: Whether to encrypt the frame (if keys are set)
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used for debugging purposes and is not
- * required to be implemented for normal operations.
- */
- int (*send_frame)(void *priv, const u8 *data, size_t data_len,
- int encrypt);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -3470,6 +3759,12 @@ struct wpa_driver_ops {
unsigned int val);
/**
+ * get_wowlan - Get wake-on-wireless status
+ * @priv: Private driver interface data
+ */
+ int (*get_wowlan)(void *priv);
+
+ /**
* set_wowlan - Set wake-on-wireless triggers
* @priv: Private driver interface data
* @triggers: wowlan triggers
@@ -3522,6 +3817,8 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* @vendor_id: Vendor id
* @subcmd: Vendor command id
+ * @nested_attr_flag: Specifies if vendor subcommand uses nested
+ * attributes or not
* @data: Vendor command parameters (%NULL if no parameters)
* @data_len: Data length
* @buf: Return buffer (%NULL to ignore reply)
@@ -3529,9 +3826,10 @@ struct wpa_driver_ops {
*
* This function handles vendor specific commands that are passed to
* the driver/device. The command is identified by vendor id and
- * command id. Parameters can be passed as argument to the command
- * in the data buffer. Reply (if any) will be filled in the supplied
- * return buffer.
+ * command id. The nested_attr_flag specifies whether the subcommand
+ * uses nested attributes or not. Parameters can be passed
+ * as argument to the command in the data buffer. Reply (if any) will be
+ * filled in the supplied return buffer.
*
* The exact driver behavior is driver interface and vendor specific. As
* an example, this will be converted to a vendor specific cfg80211
@@ -3539,6 +3837,7 @@ struct wpa_driver_ops {
*/
int (*vendor_cmd)(void *priv, unsigned int vendor_id,
unsigned int subcmd, const u8 *data, size_t data_len,
+ enum nested_attr nested_attr_flag,
struct wpabuf *buf);
/**
@@ -3829,30 +4128,30 @@ struct wpa_driver_ops {
/**
* enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_protect_frames)(void *priv, Boolean enabled);
+ int (*enable_protect_frames)(void *priv, bool enabled);
/**
* enable_encrypt - Set encryption status
* @priv: Private driver interface data
- * @enabled: TRUE = encrypt outgoing traffic
- * FALSE = integrity-only protection on outgoing traffic
+ * @enabled: true = encrypt outgoing traffic
+ * false = integrity-only protection on outgoing traffic
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_encrypt)(void *priv, Boolean enabled);
+ int (*enable_encrypt)(void *priv, bool enabled);
/**
* set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
- * @enabled: TRUE = replay protect enabled
- * FALSE = replay protect disabled
+ * @enabled: true = replay protect enabled
+ * false = replay protect disabled
* @window: replay window size, valid only when replay protect enabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_replay_protect)(void *priv, Boolean enabled, u32 window);
+ int (*set_replay_protect)(void *priv, bool enabled, u32 window);
/**
* set_current_cipher_suite - Set current cipher suite
@@ -3865,11 +4164,11 @@ struct wpa_driver_ops {
/**
* enable_controlled_port - Set controlled port status
* @priv: Private driver interface data
- * @enabled: TRUE = controlled port enabled
- * FALSE = controlled port disabled
+ * @enabled: true = controlled port enabled
+ * false = controlled port disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_controlled_port)(void *priv, Boolean enabled);
+ int (*enable_controlled_port)(void *priv, bool enabled);
/**
* get_receive_lowest_pn - Get receive lowest pn
@@ -4054,12 +4353,12 @@ struct wpa_driver_ops {
int (*do_acs)(void *priv, struct drv_acs_params *params);
/**
- * set_band - Notify driver of band selection
+ * set_band - Notify driver of band(s) selection
* @priv: Private driver interface data
- * @band: The selected band(s)
+ * @band_mask: The selected band(s) bit mask (from enum set_band)
* Returns 0 on success, -1 on failure
*/
- int (*set_band)(void *priv, enum set_band band);
+ int (*set_band)(void *priv, u32 band_mask);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
@@ -4192,13 +4491,13 @@ struct wpa_driver_ops {
int (*ignore_assoc_disallow)(void *priv, int ignore_disallow);
/**
- * set_bssid_blacklist - Set blacklist of BSSIDs to the driver
+ * set_bssid_tmp_disallow - Set disallowed BSSIDs to the driver
* @priv: Private driver interface data
- * @num_bssid: Number of blacklist BSSIDs
- * @bssids: List of blacklisted BSSIDs
+ * @num_bssid: Number of temporarily disallowed BSSIDs
+ * @bssids: List of temporarily disallowed BSSIDs
*/
- int (*set_bssid_blacklist)(void *priv, unsigned int num_bssid,
- const u8 *bssid);
+ int (*set_bssid_tmp_disallow)(void *priv, unsigned int num_bssid,
+ const u8 *bssid);
/**
* update_connect_params - Update the connection parameters
@@ -4250,6 +4549,23 @@ struct wpa_driver_ops {
*/
int (*update_dh_ie)(void *priv, const u8 *peer_mac, u16 reason_code,
const u8 *ie, size_t ie_len);
+
+ /**
+ * dpp_listen - Notify driver about start/stop of DPP listen
+ * @priv: Private driver interface data
+ * @enable: Whether listen state is enabled (or disabled)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional callback can be used to update RX frame filtering to
+ * explicitly allow reception of broadcast Public Action frames.
+ */
+ int (*dpp_listen)(void *priv, bool enable);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ int (*register_frame)(void *priv, u16 type,
+ const u8 *match, size_t match_len,
+ bool multicast);
+#endif /* CONFIG_TESTING_OPTIONS */
};
/**
@@ -4800,6 +5116,15 @@ enum wpa_event_type {
* EVENT_UPDATE_DH - Notification of updated DH information
*/
EVENT_UPDATE_DH,
+
+ /**
+ * EVENT_UNPROT_BEACON - Unprotected Beacon frame received
+ *
+ * This event should be called when a Beacon frame is dropped due to it
+ * not being protected correctly. union wpa_event_data::unprot_beacon
+ * is required to provide more details of the frame.
+ */
+ EVENT_UNPROT_BEACON,
};
@@ -4836,6 +5161,34 @@ struct freq_survey {
#define SURVEY_HAS_CHAN_TIME_RX BIT(3)
#define SURVEY_HAS_CHAN_TIME_TX BIT(4)
+/**
+ * enum sta_connect_fail_reason_codes - STA connect failure reason code values
+ * @STA_CONNECT_FAIL_REASON_UNSPECIFIED: No reason code specified for
+ * connection failure.
+ * @STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received
+ * for unicast Probe Request frame.
+ * @STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request.
+ * @STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for
+ * auth request.
+ * @STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not
+ * received from AP.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send
+ * Association Request frame.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for
+ * Association Request frame.
+ * @STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response
+ * frame is not received from AP.
+ */
+enum sta_connect_fail_reason_codes {
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED = 0,
+ STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1,
+ STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2,
+ STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3,
+ STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4,
+ STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5,
+ STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6,
+ STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7,
+};
/**
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
@@ -5237,6 +5590,11 @@ union wpa_event_data {
* FILS ERP messages
*/
u16 fils_erp_next_seq_num;
+
+ /**
+ * reason_code - Connection failure reason code from the driver
+ */
+ enum sta_connect_fail_reason_codes reason_code;
} assoc_reject;
struct timeout_event {
@@ -5564,18 +5922,28 @@ union wpa_event_data {
/**
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
- * @pri_channel: Selected primary channel
- * @sec_channel: Selected secondary channel
+ * @pri_freq: Selected primary frequency
+ * @sec_freq: Selected secondary frequency
+ * @edmg_channel: Selected EDMG channel
* @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center
+ * frequency index of the primary 80 MHz segment for 160 MHz and
+ * 80+80 MHz channels.
* @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. The
+ * value is the index of the channel center frequency for 160 MHz
+ * channels and the center frequency index of the secondary 80 MHz
+ * segment for 80+80 MHz channels.
* @ch_width: Selected Channel width by driver. Driver may choose to
* change hostapd configured ACS channel width due driver internal
* channel restrictions.
* hw_mode: Selected band (used with hw_mode=any)
*/
struct acs_selected_channels {
- u8 pri_channel;
- u8 sec_channel;
+ unsigned int pri_freq;
+ unsigned int sec_freq;
+ u8 edmg_channel;
u8 vht_seg0_center_ch;
u8 vht_seg1_center_ch;
u16 ch_width;
@@ -5642,6 +6010,13 @@ union wpa_event_data {
const u8 *ie;
size_t ie_len;
} update_dh;
+
+ /**
+ * struct unprot_beacon - Data for EVENT_UNPROT_BEACON
+ */
+ struct unprot_beacon {
+ const u8 *sa;
+ } unprot_beacon;
};
/**
@@ -5725,6 +6100,7 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
/* Convert driver flag to string */
const char * driver_flag_to_string(u64 flag);
+const char * driver_flag2_to_string(u64 flag2);
/* NULL terminated array of linked in driver wrappers */
extern const struct wpa_driver_ops *const wpa_drivers[];
diff --git a/contrib/wpa/src/drivers/driver_atheros.c b/contrib/wpa/src/drivers/driver_atheros.c
index 840d4ff4057e..9b4166d22947 100644
--- a/contrib/wpa/src/drivers/driver_atheros.c
+++ b/contrib/wpa/src/drivers/driver_atheros.c
@@ -59,10 +59,6 @@
#include "netlink.h"
#include "linux_ioctl.h"
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS)
-#define ATHEROS_USE_RAW_RECEIVE
-#endif
-
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -366,13 +362,11 @@ atheros_configure_wpa(struct atheros_driver_data *drv,
v = 0;
if (params->rsn_preauth)
v |= BIT(0);
-#ifdef CONFIG_IEEE80211W
if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
v |= BIT(7);
if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
v |= BIT(6);
}
-#endif /* CONFIG_IEEE80211W */
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
@@ -498,14 +492,18 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx)
}
static int
-atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+atheros_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct atheros_driver_data *drv = priv;
struct ieee80211req_key wk;
u_int8_t cipher;
int ret;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
if (alg == WPA_ALG_NONE)
return atheros_del_key(drv, addr, key_idx);
@@ -534,8 +532,7 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
cipher = IEEE80211_CIPHER_AES_GCM_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#ifdef CONFIG_IEEE80211W
- case WPA_ALG_IGTK:
+ case WPA_ALG_BIP_CMAC_128:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
#ifdef ATH_GCM_SUPPORT
@@ -549,7 +546,6 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
cipher = IEEE80211_CIPHER_AES_GMAC_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
__func__, alg);
@@ -856,7 +852,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
return 0;
}
-#ifdef ATHEROS_USE_RAW_RECEIVE
+
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -953,7 +949,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
break;
}
}
-#endif /* ATHEROS_USE_RAW_RECEIVE */
+
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -965,11 +961,9 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1069,7 +1063,6 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
static int
atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
{
@@ -1169,7 +1162,7 @@ atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
}
return ret;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
+
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1315,7 +1308,6 @@ 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) || defined(CONFIG_FILS)
} else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
@@ -1339,8 +1331,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
-#ifdef ATHEROS_USE_RAW_RECEIVE
} else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
@@ -1353,7 +1343,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1973,11 +1962,10 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
-
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
int noack, unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
@@ -1999,7 +1987,6 @@ 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 || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
@@ -2283,11 +2270,9 @@ 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,
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c
index 96cf066a7a46..16502b945212 100644
--- a/contrib/wpa/src/drivers/driver_bsd.c
+++ b/contrib/wpa/src/drivers/driver_bsd.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include <sys/ioctl.h>
-#include <sys/sysctl.h>
#include "common.h"
#include "driver.h"
@@ -17,7 +16,9 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
+#include <ifaddrs.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_media.h>
#ifdef __NetBSD__
@@ -51,22 +52,19 @@ struct bsd_driver_global {
void *ctx;
int sock; /* socket for 802.11 ioctls */
int route; /* routing socket for events */
- char *event_buf;
- size_t event_buf_len;
struct dl_list ifaces; /* list of interfaces */
};
struct bsd_driver_data {
struct dl_list list;
struct bsd_driver_global *global;
- struct hostapd_data *hapd; /* back pointer */
+ void *ctx;
struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
char ifname[IFNAMSIZ+1]; /* interface name */
int flags;
unsigned int ifindex; /* interface index */
int if_removed; /* has the interface been removed? */
- void *ctx;
struct wpa_driver_capa capa; /* driver capability */
int is_ap; /* Access point mode */
int prev_roaming; /* roaming state to restore on deinit */
@@ -76,6 +74,7 @@ struct bsd_driver_data {
};
/* Generic functions for hostapd and wpa_supplicant */
+
static struct bsd_driver_data *
bsd_get_drvindex(void *priv, unsigned int ifindex)
{
@@ -89,7 +88,6 @@ bsd_get_drvindex(void *priv, unsigned int ifindex)
return NULL;
}
-#ifndef HOSTAPD
static struct bsd_driver_data *
bsd_get_drvname(void *priv, const char *ifname)
{
@@ -102,7 +100,6 @@ bsd_get_drvname(void *priv, const char *ifname)
}
return NULL;
}
-#endif /* HOSTAPD */
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
@@ -142,7 +139,9 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
ireq->i_data = arg;
if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
+ int level = drv->if_removed ? MSG_DEBUG : MSG_ERROR;
+
+ wpa_printf(level, "ioctl[SIOCG80211, op=%u, "
"arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
@@ -294,9 +293,8 @@ bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
}
static int
-bsd_ctrl_iface(void *priv, int enable)
+bsd_get_iface_flags(struct bsd_driver_data *drv)
{
- struct bsd_driver_data *drv = priv;
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
@@ -308,36 +306,24 @@ bsd_ctrl_iface(void *priv, int enable)
return -1;
}
drv->flags = ifr.ifr_flags;
-
- if (enable) {
- if (ifr.ifr_flags & IFF_UP)
- return 0;
- ifr.ifr_flags |= IFF_UP;
- } else {
- if (!(ifr.ifr_flags & IFF_UP))
- return 0;
- ifr.ifr_flags &= ~IFF_UP;
- }
-
- if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- return -1;
- }
-
- drv->flags = ifr.ifr_flags;
return 0;
}
static int
-bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+bsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct ieee80211req_key wk;
#ifdef IEEE80211_KEY_NOREPLAY
struct bsd_driver_data *drv = priv;
#endif /* IEEE80211_KEY_NOREPLAY */
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -539,7 +525,7 @@ bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
__func__);
return -1;
}
- return bsd_ctrl_iface(priv, 1);
+ return 0;
}
static void
@@ -594,17 +580,13 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
if (channel < 14) {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NG :
-#endif /* CONFIG_IEEE80211N */
- IFM_IEEE80211_11G;
+ IFM_IEEE80211_11G;
} else if (channel == 14) {
mode = IFM_IEEE80211_11B;
} else {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NA :
-#endif /* CONFIG_IEEE80211N */
IFM_IEEE80211_11A;
}
if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
@@ -635,20 +617,262 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
return 0;
}
-static size_t
-rtbuf_len(void)
+#ifdef SO_RERROR
+static void
+bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global)
{
- size_t len;
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ int n;
+ struct ifaddrs *ifaddrs, *ifa;
+ struct bsd_driver_data *drv;
+ struct sockaddr_dl *sdl;
+ union wpa_event_data event;
- int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
+ /* We need to match the system state, so drain the route
+ * socket to avoid stale messages. */
+ do {
+ n = read(sock, event_buf, sizeof(event_buf));
+ } while (n != -1 || errno == ENOBUFS);
- if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
- strerror(errno));
- len = 2048;
+ if (getifaddrs(&ifaddrs) == -1) {
+ wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ /* add or update existing interfaces */
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ drv = bsd_get_drvname(global, ifa->ifa_name);
+ if (drv != NULL &&
+ (drv->ifindex != sdl->sdl_index || drv->if_removed)) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' added",
+ drv->ifname);
+ drv->ifindex = sdl->sdl_index;
+ drv->if_removed = 0;
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ os_strlcpy(event.interface_status.ifname, ifa->ifa_name,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!drv &&
+ (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) {
+ /* Driver name is invalid */
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ }
+
+ /* punt missing interfaces and update flags */
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ if (os_strcmp(drv->ifname, ifa->ifa_name) == 0)
+ break;
+ }
+ if (ifa == NULL && !drv->if_removed) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!ifa)
+ continue;
+
+ if ((ifa->ifa_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifa->ifa_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifa->ifa_flags;
}
- return (len == 0) ? 2048 : len;
+ freeifaddrs(ifaddrs);
+}
+#endif /* SO_RERROR */
+
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ struct bsd_driver_global *global = sock_ctx;
+ struct bsd_driver_data *drv;
+ struct if_announcemsghdr *ifan;
+ struct if_msghdr *ifm;
+ struct rt_msghdr *rtm;
+ union wpa_event_data event;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_leave_event *leave;
+ struct ieee80211_join_event *join;
+ int n;
+
+ n = read(sock, event_buf, sizeof(event_buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
+ __func__, strerror(errno));
+#ifdef SO_RERROR
+ if (errno == ENOBUFS)
+ bsd_route_overflow(sock, ctx, sock_ctx);
+#endif /* SO_RERROR */
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) event_buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+ rtm->rtm_version);
+ return;
+ }
+ os_memset(&event, 0, sizeof(event));
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ break;
+ case RTM_IEEE80211_DISASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
+ case RTM_IEEE80211_SCAN:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ drv_event_disassoc(drv->ctx, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, drv->ctx, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ os_memset(&event, 0, sizeof(event));
+ event.michael_mic_failure.unicast =
+ !IEEE80211_IS_MULTICAST(mic->iev_dst);
+ event.michael_mic_failure.src = mic->iev_src;
+ wpa_supplicant_event(drv->ctx,
+ EVENT_MICHAEL_MIC_FAILURE, &event);
+ break;
+ }
+ break;
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (ifan->ifan_what) {
+ case IFAN_DEPARTURE:
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv)
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv) {
+ drv->ifindex = ifan->ifan_index;
+ drv->if_removed = 0;
+ }
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+ ifan->ifan_name,
+ ifan->ifan_what == IFAN_DEPARTURE ?
+ "removed" : "added");
+ os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+ sizeof(event.interface_status.ifname));
+ if (drv) {
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ /*
+ * Set ifindex to zero after sending the event as the
+ * event might query the driver to ensure a match.
+ */
+ if (ifan->ifan_what == IFAN_DEPARTURE)
+ drv->ifindex = 0;
+ } else {
+ wpa_supplicant_event_global(global->ctx,
+ EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ break;
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifm->ifm_index);
+ if (drv == NULL)
+ return;
+ if (((ifm->ifm_flags & IFF_UP) == 0 ||
+ (ifm->ifm_flags & IFF_RUNNING) == 0) &&
+ (drv->flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_RUNNING) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+ (ifm->ifm_flags & IFF_RUNNING) != 0 &&
+ ((drv->flags & IFF_UP) == 0 ||
+ (drv->flags & IFF_RUNNING) == 0)) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifm->ifm_flags;
+ break;
+ }
}
#ifdef HOSTAPD
@@ -769,80 +993,10 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
}
static void
-bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct rt_msghdr *rtm;
- struct ieee80211_michael_event *mic;
- struct ieee80211_join_event *join;
- struct ieee80211_leave_event *leave;
- int n;
- union wpa_event_data data;
-
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- switch (rtm->rtm_type) {
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- case RTM_IEEE80211_DISASSOC:
- case RTM_IEEE80211_SCAN:
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->hapd, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->hapd, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
- os_memset(&data, 0, sizeof(data));
- data.michael_mic_failure.unicast = 1;
- data.michael_mic_failure.src = mic->iev_src;
- wpa_supplicant_event(drv->hapd,
- EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- }
- break;
- }
-}
-
-static void
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
{
struct bsd_driver_data *drv = ctx;
- drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+ drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
}
static void *
@@ -863,7 +1017,8 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
goto bad;
}
- drv->hapd = hapd;
+ drv->ctx = hapd;
+ drv->is_ap = 1;
drv->global = params->global_priv;
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -874,8 +1029,7 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
goto bad;
- /* mark down during setup */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto bad;
if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
@@ -900,8 +1054,6 @@ bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
- if (drv->ifindex != 0)
- bsd_ctrl_iface(drv, 0);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
os_free(drv);
@@ -909,13 +1061,6 @@ bsd_deinit(void *priv)
static int
-bsd_commit(void *priv)
-{
- return bsd_ctrl_iface(priv, 1);
-}
-
-
-static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and)
@@ -1079,14 +1224,7 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
mode = 0 /* STA */;
break;
case IEEE80211_MODE_IBSS:
- /*
- * Ref bin/203086 - FreeBSD's net80211 currently uses
- * IFM_IEEE80211_ADHOC.
- */
-#if 0
mode = IFM_IEEE80211_IBSS;
-#endif
- mode = IFM_IEEE80211_ADHOC;
break;
case IEEE80211_MODE_AP:
mode = IFM_IEEE80211_HOSTAP;
@@ -1133,13 +1271,6 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
return -1;
- /*
- * NB: interface must be marked UP for association
- * or scanning (ap_scan=2)
- */
- if (bsd_ctrl_iface(drv, 1) < 0)
- return -1;
-
os_memset(&mlme, 0, sizeof(mlme));
mlme.im_op = IEEE80211_MLME_ASSOC;
if (params->ssid != NULL)
@@ -1182,8 +1313,11 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
}
/* NB: interface must be marked UP to do a scan */
- if (bsd_ctrl_iface(drv, 1) < 0)
+ if (!(drv->flags & IFF_UP)) {
+ wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan",
+ __func__);
return -1;
+ }
#ifdef IEEE80211_IOC_SCAN_MAX_SSID
os_memset(&sr, 0, sizeof(sr));
@@ -1221,166 +1355,6 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
}
static void
-wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct if_msghdr *ifm;
- struct rt_msghdr *rtm;
- union wpa_event_data event;
- struct ieee80211_michael_event *mic;
- struct ieee80211_leave_event *leave;
- struct ieee80211_join_event *join;
- int n;
-
- /*
- * CID 1394785: Memory - illegal access (STRING_NULL):
- * Though global->event_buf is a char *, it actually contains
- * a struct rt_msghdr *. See below.
- */
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- /*
- * CID 1394785: global->event_buf is assigned here to a
- * struct rt_msghdr *.
- */
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- os_memset(&event, 0, sizeof(event));
- switch (rtm->rtm_type) {
- case RTM_IFANNOUNCE:
- ifan = (struct if_announcemsghdr *) rtm;
- switch (ifan->ifan_what) {
- case IFAN_DEPARTURE:
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv)
- drv->if_removed = 1;
- event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
- break;
- case IFAN_ARRIVAL:
- drv = bsd_get_drvname(global, ifan->ifan_name);
- if (drv) {
- drv->ifindex = ifan->ifan_index;
- drv->if_removed = 0;
- }
- event.interface_status.ievent = EVENT_INTERFACE_ADDED;
- break;
- default:
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
- return;
- }
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
- ifan->ifan_name,
- ifan->ifan_what == IFAN_DEPARTURE ?
- "removed" : "added");
- os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
- sizeof(event.interface_status.ifname));
- if (drv) {
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
- &event);
- /*
- * Set ifindex to zero after sending the event as the
- * event might query the driver to ensure a match.
- */
- if (ifan->ifan_what == IFAN_DEPARTURE)
- drv->ifindex = 0;
- } else {
- wpa_supplicant_event_global(global->ctx,
- EVENT_INTERFACE_STATUS,
- &event);
- }
- break;
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
- break;
- case RTM_IEEE80211_DISASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- break;
- case RTM_IEEE80211_SCAN:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
- NULL);
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->ctx, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->ctx, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
-
- os_memset(&event, 0, sizeof(event));
- event.michael_mic_failure.unicast =
- !IEEE80211_IS_MULTICAST(mic->iev_dst);
- wpa_supplicant_event(drv->ctx,
- EVENT_MICHAEL_MIC_FAILURE, &event);
- break;
- }
- break;
- case RTM_IFINFO:
- ifm = (struct if_msghdr *) rtm;
- drv = bsd_get_drvindex(global, ifm->ifm_index);
- if (drv == NULL)
- return;
- if (((ifm->ifm_flags & IFF_UP) == 0 ||
- (ifm->ifm_flags & IFF_RUNNING) == 0) &&
- (drv->flags & IFF_UP) != 0 &&
- (drv->flags & IFF_RUNNING) != 0) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
- NULL);
- } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
- (ifm->ifm_flags & IFF_RUNNING) != 0 &&
- ((drv->flags & IFF_UP) == 0 ||
- (drv->flags & IFF_RUNNING) == 0)) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
- NULL);
- }
- drv->flags = ifm->ifm_flags;
- break;
- }
-}
-
-static void
wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
struct ieee80211req_scan_result *sr)
{
@@ -1516,17 +1490,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-#ifdef __FreeBSD__
- drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP |
- WPA_DRIVER_CAPA_ENC_CCMP;
-#else
- /*
- * XXX
- * FreeBSD exports hardware cryptocaps. These have no meaning for wpa
- * since net80211 performs software crypto.
- */
if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
WPA_DRIVER_CAPA_ENC_WEP104;
@@ -1534,7 +1497,6 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-#endif
if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
@@ -1587,8 +1549,6 @@ get80211opmode(struct bsd_driver_data *drv)
}
if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
return IEEE80211_M_HOSTAP;
- if (ifmr.ifm_current & IFM_IEEE80211_IBSS)
- return IEEE80211_M_IBSS;
if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
return IEEE80211_M_MONITOR;
#ifdef IEEE80211_M_MBSS
@@ -1605,17 +1565,12 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
#define GETPARAM(drv, param, v) \
(((v) = get80211param(drv, param)) != -1)
struct bsd_driver_data *drv;
+ int i;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- /*
- * NB: We require the interface name be mappable to an index.
- * This implies we do not support having wpa_supplicant
- * wait for an interface to appear. This seems ok; that
- * doesn't belong here; it's really the job of devd.
- */
drv->ifindex = if_nametoindex(ifname);
if (drv->ifindex == 0) {
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
@@ -1627,6 +1582,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
drv->global = priv;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ /* Set the interface as removed until proven to work. */
+ drv->if_removed = 1;
+
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
__func__, strerror(errno));
@@ -1646,10 +1604,17 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
if (wpa_driver_bsd_capa(drv))
goto fail;
+ /* Update per interface supported AKMs */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
+
/* Down interface during setup. */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto fail;
+ /* Proven to work, lets go! */
+ drv->if_removed = 0;
+
drv->opmode = get80211opmode(drv);
dl_list_add(&drv->global->ifaces, &drv->list);
@@ -1668,9 +1633,6 @@ wpa_driver_bsd_deinit(void *priv)
if (drv->ifindex != 0 && !drv->if_removed) {
wpa_driver_bsd_set_wpa(drv, 0);
- /* NB: mark interface down */
- bsd_ctrl_iface(drv, 0);
-
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
drv->prev_privacy);
@@ -1701,6 +1663,15 @@ static void *
bsd_global_init(void *ctx)
{
struct bsd_driver_global *global;
+#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
+ unsigned char msgfilter[] = {
+ RTM_IEEE80211,
+ RTM_IFINFO, RTM_IFANNOUNCE,
+ };
+#endif
+#ifdef ROUTE_MSGFILTER
+ unsigned int i, msgfilter_mask;
+#endif
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -1709,36 +1680,39 @@ bsd_global_init(void *ctx)
global->ctx = ctx;
dl_list_init(&global->ifaces);
- global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ global->sock = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (global->sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
strerror(errno));
goto fail1;
}
- global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ global->route = socket(PF_ROUTE,
+ SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (global->route < 0) {
wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
strerror(errno));
goto fail;
}
- global->event_buf_len = rtbuf_len();
- global->event_buf = os_malloc(global->event_buf_len);
- if (global->event_buf == NULL) {
- wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
- goto fail;
- }
+#if defined(RO_MSGFILTER)
+ if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER,
+ &msgfilter, sizeof(msgfilter)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s",
+ strerror(errno));
+#elif defined(ROUTE_MSGFILTER)
+ msgfilter_mask = 0;
+ for (i = 0; i < (sizeof(msgfilter) / sizeof(msgfilter[0])); i++)
+ msgfilter_mask |= ROUTE_FILTER(msgfilter[i]);
+ if (setsockopt(global->route, PF_ROUTE, ROUTE_MSGFILTER,
+ &msgfilter_mask, sizeof(msgfilter_mask)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,ROUTE_MSGFILTER]: %s",
+ strerror(errno));
+#endif
-#ifdef HOSTAPD
eloop_register_read_sock(global->route, bsd_wireless_event_receive,
NULL, global);
-#else /* HOSTAPD */
- eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
- NULL, global);
-#endif /* HOSTAPD */
-
return global;
fail:
@@ -1775,7 +1749,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
.sta_disassoc = bsd_sta_disassoc,
.sta_deauth = bsd_sta_deauth,
.sta_set_flags = bsd_set_sta_authorized,
- .commit = bsd_commit,
#else /* HOSTAPD */
.init2 = wpa_driver_bsd_init,
.deinit = wpa_driver_bsd_deinit,
diff --git a/contrib/wpa/src/drivers/driver_common.c b/contrib/wpa/src/drivers/driver_common.c
index 731c6a3b16bd..a7ebe956680b 100644
--- a/contrib/wpa/src/drivers/driver_common.c
+++ b/contrib/wpa/src/drivers/driver_common.c
@@ -89,6 +89,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(INTERFACE_MAC_CHANGED);
E2S(WDS_STA_INTERFACE_STATUS);
E2S(UPDATE_DH);
+ E2S(UNPROT_BEACON);
}
return "UNKNOWN";
@@ -308,6 +309,26 @@ const char * driver_flag_to_string(u64 flag)
DF2S(OCE_AP);
DF2S(OCE_STA_CFON);
DF2S(MFP_OPTIONAL);
+ DF2S(SELF_MANAGED_REGULATORY);
+ DF2S(FTM_RESPONDER);
+ DF2S(CONTROL_PORT);
+ DF2S(VLAN_OFFLOAD);
+ DF2S(UPDATE_FT_IES);
+ DF2S(SAFE_PTK0_REKEYS);
+ DF2S(BEACON_PROTECTION);
+ DF2S(EXTENDED_KEY_ID);
+ }
+ return "UNKNOWN";
+#undef DF2S
+}
+
+
+const char * driver_flag2_to_string(u64 flag2)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x
+ switch (flag2) {
+ DF2S(CONTROL_PORT_RX);
+ DF2S(CONTROL_PORT_TX_STATUS);
}
return "UNKNOWN";
#undef DF2S
diff --git a/contrib/wpa/src/drivers/driver_hostap.c b/contrib/wpa/src/drivers/driver_hostap.c
index 186eccbf2181..b9c42e4db48d 100644
--- a/contrib/wpa/src/drivers/driver_hostap.c
+++ b/contrib/wpa/src/drivers/driver_hostap.c
@@ -263,7 +263,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -312,7 +313,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
@@ -395,17 +396,20 @@ static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
}
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_hostap_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param *param;
u8 *buf;
size_t blen;
int ret = 0;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
blen = sizeof(*param) + key_len;
buf = os_zalloc(blen);
@@ -1051,7 +1055,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
+ sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0);
}
@@ -1089,7 +1093,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
+ sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0);
}
@@ -1169,7 +1173,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0);
}
diff --git a/contrib/wpa/src/drivers/driver_hostap.h b/contrib/wpa/src/drivers/driver_hostap.h
new file mode 100644
index 000000000000..4c1e6d69f0a7
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_hostap.h
@@ -0,0 +1,210 @@
+/*
+ * Driver interaction with Linux Host AP driver
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAP_DRIVER_H
+#define HOSTAP_DRIVER_H
+
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+ HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+ AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+ AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+ PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+ /* Note! Old versions of prism2_srec have a fatal error in CRC-16
+ * calculation, which will corrupt all non-volatile downloads.
+ * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+ * prevent use of old versions of prism2_srec for non-volatile
+ * download. */
+ PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+ /* Persistent versions of volatile download commands (keep firmware
+ * data in memory and automatically re-download after hw_reset */
+ PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+ u32 dl_cmd;
+ u32 start_addr;
+ u32 num_areas;
+ struct prism2_download_area {
+ u32 addr; /* wlan card address */
+ u32 len;
+ caddr_t ptr; /* pointer to data in user space */
+ } data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[SSID_MAX_LEN];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#endif /* HOSTAP_DRIVER_H */
diff --git a/contrib/wpa/src/drivers/driver_macsec_linux.c b/contrib/wpa/src/drivers/driver_macsec_linux.c
index e922503fccd0..3dba13ce7028 100644
--- a/contrib/wpa/src/drivers/driver_macsec_linux.c
+++ b/contrib/wpa/src/drivers/driver_macsec_linux.c
@@ -54,31 +54,29 @@ struct macsec_drv_data {
struct nl_sock *sk;
struct macsec_genl_ctx ctx;
- struct netlink_data *netlink;
- struct nl_handle *nl;
char ifname[IFNAMSIZ + 1];
int ifi;
int parent_ifi;
int use_pae_group_addr;
- Boolean created_link;
+ bool created_link;
- Boolean controlled_port_enabled;
- Boolean controlled_port_enabled_set;
+ bool controlled_port_enabled;
+ bool controlled_port_enabled_set;
- Boolean protect_frames;
- Boolean protect_frames_set;
+ bool protect_frames;
+ bool protect_frames_set;
- Boolean encrypt;
- Boolean encrypt_set;
+ bool encrypt;
+ bool encrypt_set;
- Boolean replay_protect;
- Boolean replay_protect_set;
+ bool replay_protect;
+ bool replay_protect_set;
u32 replay_window;
u8 encoding_sa;
- Boolean encoding_sa_set;
+ bool encoding_sa_set;
};
@@ -199,7 +197,7 @@ static int try_commit(struct macsec_drv_data *drv)
rtnl_link_put(change);
- drv->controlled_port_enabled_set = FALSE;
+ drv->controlled_port_enabled_set = false;
}
if (drv->protect_frames_set) {
@@ -238,9 +236,9 @@ static int try_commit(struct macsec_drv_data *drv)
if (err < 0)
return err;
- drv->protect_frames_set = FALSE;
- drv->encrypt_set = FALSE;
- drv->replay_protect_set = FALSE;
+ drv->protect_frames_set = false;
+ drv->encrypt_set = false;
+ drv->replay_protect_set = false;
return 0;
}
@@ -321,14 +319,14 @@ static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX
"Unable to connect NETLINK_ROUTE socket: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
@@ -392,17 +390,17 @@ static int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
/**
* macsec_drv_enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
+static int macsec_drv_enable_protect_frames(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
- drv->protect_frames_set = TRUE;
+ drv->protect_frames_set = true;
drv->protect_frames = enabled;
return try_commit(drv);
@@ -412,17 +410,17 @@ static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
/**
* macsec_drv_enable_encrypt - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
+static int macsec_drv_enable_encrypt(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
- drv->encrypt_set = TRUE;
+ drv->encrypt_set = true;
drv->encrypt = enabled;
return try_commit(drv);
@@ -432,12 +430,12 @@ static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
/**
* macsec_drv_set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
- * @enabled: TRUE = replay protect enabled
- * FALSE = replay protect disabled
+ * @enabled: true = replay protect enabled
+ * false = replay protect disabled
* @window: replay window size, valid only when replay protect enabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
+static int macsec_drv_set_replay_protect(void *priv, bool enabled,
u32 window)
{
struct macsec_drv_data *drv = priv;
@@ -445,7 +443,7 @@ static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
enabled ? "TRUE" : "FALSE", window);
- drv->replay_protect_set = TRUE;
+ drv->replay_protect_set = true;
drv->replay_protect = enabled;
if (enabled)
drv->replay_window = window;
@@ -470,18 +468,18 @@ static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
/**
* macsec_drv_enable_controlled_port - Set controlled port status
* @priv: Private driver interface data
- * @enabled: TRUE = controlled port enabled
- * FALSE = controlled port disabled
+ * @enabled: true = controlled port enabled
+ * false = controlled port disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
+static int macsec_drv_enable_controlled_port(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
drv->controlled_port_enabled = enabled;
- drv->controlled_port_enabled_set = TRUE;
+ drv->controlled_port_enabled_set = true;
return try_commit(drv);
}
@@ -714,6 +712,9 @@ static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
if (!msg)
return ret;
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
if (!nest)
goto nla_put_failure;
@@ -988,7 +989,7 @@ nla_put_failure:
static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
- u64 sci, unsigned char an, Boolean state)
+ u64 sci, unsigned char an, bool state)
{
struct nl_msg *msg;
struct nlattr *nest;
@@ -1038,7 +1039,7 @@ static int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
- sa->an, TRUE);
+ sa->an, true);
}
@@ -1058,7 +1059,7 @@ static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
- sa->an, FALSE);
+ sa->an, false);
}
@@ -1119,13 +1120,13 @@ static int macsec_drv_create_transmit_sc(
sci = mka_sci_u64(&sc->sci);
rtnl_link_macsec_set_sci(link, sci);
- drv->created_link = TRUE;
+ drv->created_link = true;
err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
if (err == -NLE_BUSY) {
wpa_printf(MSG_INFO,
DRV_PREFIX "link already exists, using it");
- drv->created_link = FALSE;
+ drv->created_link = false;
} else if (err < 0) {
rtnl_link_put(link);
wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
@@ -1298,7 +1299,7 @@ nla_put_failure:
static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
- unsigned char an, Boolean state)
+ unsigned char an, bool state)
{
struct nl_msg *msg;
struct nlattr *nest;
@@ -1346,13 +1347,13 @@ static int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
- ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
+ ret = set_active_tx_sa(ctx, drv->ifi, sa->an, true);
if (ret < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
return ret;
}
- drv->encoding_sa_set = TRUE;
+ drv->encoding_sa_set = true;
drv->encoding_sa = sa->an;
return try_commit(drv);
@@ -1374,7 +1375,7 @@ static int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
- return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
+ return set_active_tx_sa(ctx, drv->ifi, sa->an, false);
}
diff --git a/contrib/wpa/src/drivers/driver_macsec_qca.c b/contrib/wpa/src/drivers/driver_macsec_qca.c
index f4e55d5d99a1..928f02499510 100644
--- a/contrib/wpa/src/drivers/driver_macsec_qca.c
+++ b/contrib/wpa/src/drivers/driver_macsec_qca.c
@@ -70,11 +70,11 @@ struct macsec_qca_data {
u32 secy_id;
/* shadow */
- Boolean always_include_sci;
- Boolean use_es;
- Boolean use_scb;
- Boolean protect_frames;
- Boolean replay_protect;
+ bool always_include_sci;
+ bool use_es;
+ bool use_scb;
+ bool protect_frames;
+ bool replay_protect;
u32 replay_window;
struct channel_map receive_channel_map[MAXSC];
@@ -91,7 +91,7 @@ static void __macsec_drv_init(struct macsec_qca_data *drv)
wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
/* Enable Secy and Let EAPoL bypass */
- ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
+ ret = nss_macsec_secy_en_set(drv->secy_id, true);
if (ret)
wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
@@ -123,7 +123,7 @@ static void __macsec_drv_init(struct macsec_qca_data *drv)
static void __macsec_drv_deinit(struct macsec_qca_data *drv)
{
- nss_macsec_secy_en_set(drv->secy_id, FALSE);
+ nss_macsec_secy_en_set(drv->secy_id, false);
nss_macsec_secy_rx_sc_del_all(drv->secy_id);
nss_macsec_secy_tx_sc_del_all(drv->secy_id);
}
@@ -422,7 +422,7 @@ static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
}
-static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
+static int macsec_qca_enable_protect_frames(void *priv, bool enabled)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
@@ -435,7 +435,7 @@ static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
}
-static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
+static int macsec_qca_set_replay_protect(void *priv, bool enabled,
unsigned int window)
{
struct macsec_qca_data *drv = priv;
@@ -480,7 +480,7 @@ static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
}
-static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
+static int macsec_qca_enable_controlled_port(void *priv, bool enabled)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
@@ -560,7 +560,7 @@ static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 next_pn = 0;
- bool enabled = FALSE;
+ bool enabled = false;
u32 win;
u32 channel;
@@ -629,7 +629,7 @@ static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 sc_ch = 0;
- bool in_use = FALSE;
+ bool in_use = false;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
@@ -794,7 +794,7 @@ static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
sa->an);
ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
- TRUE);
+ true);
return ret;
}
@@ -814,7 +814,7 @@ static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
sa->an);
ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
- FALSE);
+ false);
return ret;
}
@@ -824,7 +824,7 @@ static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
{
struct macsec_qca_data *drv = priv;
u32 sc_ch = 0;
- bool in_use = FALSE;
+ bool in_use = false;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
@@ -988,7 +988,7 @@ static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
sa->an);
ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
- TRUE);
+ true);
return ret;
}
@@ -1008,7 +1008,7 @@ static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
sa->an);
ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
- FALSE);
+ false);
return ret;
}
diff --git a/contrib/wpa/src/drivers/driver_ndis.c b/contrib/wpa/src/drivers/driver_ndis.c
index 120aa57b108b..8555f96d3283 100644
--- a/contrib/wpa/src/drivers/driver_ndis.c
+++ b/contrib/wpa/src/drivers/driver_ndis.c
@@ -58,7 +58,6 @@ static const u8 pae_group_addr[ETH_ALEN] =
/* FIX: to be removed once this can be compiled with the complete NDIS
* header files */
#ifndef OID_802_11_BSSID
-#define OID_802_3_MULTICAST_LIST 0x01010103
#define OID_802_11_BSSID 0x0d010101
#define OID_802_11_SSID 0x0d010102
#define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108
@@ -505,13 +504,13 @@ static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
o->Length = len;
if (!PacketRequest(drv->adapter, FALSE, o)) {
- wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%lu) failed",
__func__, oid, len);
os_free(buf);
return -1;
}
if (o->Length > len) {
- wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%lu)",
__func__, oid, (unsigned int) o->Length, len);
os_free(buf);
return -1;
@@ -574,7 +573,7 @@ static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
os_memcpy(o->Data, data, len);
if (!PacketRequest(drv->adapter, TRUE, o)) {
- wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%lu) failed",
__func__, oid, len);
os_free(buf);
return -1;
@@ -1035,6 +1034,18 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
static int
+wpa_driver_ndis_set_key_wrapper(void *priv,
+ struct wpa_driver_set_key_params *params)
+{
+ return wpa_driver_ndis_set_key(params->ifname, priv,
+ params->alg, params->addr,
+ params->key_idx, params->set_tx,
+ params->seq, params->seq_len,
+ params->key, params->key_len);
+}
+
+
+static int
wpa_driver_ndis_associate(void *priv,
struct wpa_driver_associate_params *params)
{
@@ -1532,7 +1543,7 @@ static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
if (data_len < sizeof(*req)) {
wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
- "Event (len=%d)", data_len);
+ "Event (len=%lu)", data_len);
return;
}
req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
@@ -1566,7 +1577,7 @@ static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
if (data_len < 8) {
wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
- "Event (len=%d)", data_len);
+ "Event (len=%lu)", data_len);
return;
}
pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
@@ -1588,7 +1599,7 @@ static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
os_memset(&event, 0, sizeof(event));
for (i = 0; i < pmkid->NumCandidates; i++) {
PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
- wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
+ wpa_printf(MSG_DEBUG, "NDIS: %lu: " MACSTR " Flags 0x%x",
i, MAC2STR(p->BSSID), (int) p->Flags);
os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
event.pmkid_candidate.index = i;
@@ -1779,7 +1790,7 @@ static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
"overflow");
break;
}
- wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
+ wpa_printf(MSG_MSGDUMP, "NDIS: %lu - auth %d encr %d",
i, (int) ae->AuthModeSupported,
(int) ae->EncryptStatusSupported);
switch (ae->AuthModeSupported) {
@@ -2107,7 +2118,11 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
dlen = dpos - desc;
else
dlen = os_strlen(desc);
- drv->adapter_desc = dup_binstr(desc, dlen);
+ drv->adapter_desc = os_malloc(dlen + 1);
+ if (drv->adapter_desc) {
+ os_memcpy(drv->adapter_desc, desc, dlen);
+ drv->adapter_desc[dlen] = '\0';
+ }
os_free(b);
if (drv->adapter_desc == NULL)
return -1;
@@ -2275,7 +2290,11 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
} else {
dlen = os_strlen(desc[i]);
}
- drv->adapter_desc = dup_binstr(desc[i], dlen);
+ drv->adapter_desc = os_malloc(dlen + 1);
+ if (drv->adapter_desc) {
+ os_memcpy(drv->adapter_desc, desc[i], dlen);
+ drv->adapter_desc[dlen] = '\0';
+ }
os_free(names);
if (drv->adapter_desc == NULL)
return -1;
@@ -2798,6 +2817,7 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
{
struct wpa_driver_ndis_data *drv;
u32 mode;
+ int i;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
@@ -2844,6 +2864,11 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
}
wpa_driver_ndis_get_capability(drv);
+ /* Update per interface supported AKMs */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
+
+
/* Make sure that the driver does not have any obsolete PMKID entries.
*/
wpa_driver_ndis_flush_pmkid(drv);
@@ -3196,7 +3221,7 @@ void driver_ndis_init_ops(void)
wpa_driver_ndis_ops.desc = ndis_drv_desc;
wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
- wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+ wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key_wrapper;
wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
diff --git a/contrib/wpa/src/drivers/driver_nl80211.c b/contrib/wpa/src/drivers/driver_nl80211.c
new file mode 100644
index 000000000000..8eb033c78cf9
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211.c
@@ -0,0 +1,12229 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/types.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#ifdef CONFIG_LIBNL3_ROUTE
+#include <netlink/route/neighbour.h>
+#endif /* CONFIG_LIBNL3_ROUTE */
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/errqueue.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "common/brcm_vendor.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
+#include "netlink.h"
+#include "linux_defines.h"
+#include "linux_ioctl.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#include "rfkill.h"
+#include "driver_nl80211.h"
+
+
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif /* NETLINK_CAP_ACK */
+/* support for extack if compilation headers are too old */
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#endif
+#ifndef NLM_F_CAPPED
+#define NLM_F_CAPPED 0x100
+#endif
+#ifndef NLM_F_ACK_TLVS
+#define NLM_F_ACK_TLVS 0x200
+#endif
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+
+#endif /* ANDROID */
+
+
+static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+ struct nl_sock *handle;
+
+ handle = nl_socket_alloc_cb(cb);
+ if (handle == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks (%s)", dbg);
+ return NULL;
+ }
+
+ if (genl_connect(handle)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink (%s)", dbg);
+ nl_socket_free(handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_sock **handle)
+{
+ if (*handle == NULL)
+ return;
+ nl_socket_free(*handle);
+ *handle = NULL;
+}
+
+
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_sock **handle,
+ eloop_sock_handler handler,
+ void *eloop_data, int persist)
+{
+ /*
+ * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
+ * by default. It is possible to hit that limit in some cases where
+ * operations are blocked, e.g., with a burst of Deauthentication frames
+ * to hostapd and STA entry deletion. Try to increase the buffer to make
+ * this less likely to occur.
+ */
+ int err;
+
+ err = nl_socket_set_buffer_size(*handle, 262144, 0);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set nl_socket RX buffer size: %s",
+ nl_geterror(err));
+ /* continue anyway with the default (smaller) buffer */
+ }
+
+ nl_socket_set_nonblocking(*handle);
+ eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+ eloop_data, *handle);
+ if (!persist)
+ *handle = (void *) (((intptr_t) *handle) ^
+ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
+{
+ if (!persist)
+ *handle = (void *) (((intptr_t) *handle) ^
+ ELOOP_SOCKET_INVALID);
+ eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+ nl_destroy_handles(handle);
+}
+
+
+static void nl80211_global_deinit(void *priv);
+static void nl80211_check_global(struct nl80211_global *global);
+
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
+ struct hostapd_freq_params *freq);
+
+static int
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+ const u8 *set_addr, int first,
+ const char *driver_params);
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+ unsigned int freq, unsigned int wait,
+ const u8 *buf, size_t buf_len,
+ int save_cookie,
+ int no_cck, int no_ack, int offchanok,
+ const u16 *csa_offs, size_t csa_offs_len);
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
+ int report);
+
+#define IFIDX_ANY -1
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason);
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason);
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason);
+
+static int nl80211_set_channel(struct i802_bss *bss,
+ struct hostapd_freq_params *freq, int set_chan);
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int disabled);
+
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode);
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up);
+static int nl80211_set_param(void *priv, const char *param);
+#ifdef CONFIG_MESH
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params);
+#endif /* CONFIG_MESH */
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ u16 reason);
+
+
+/* Converts nl80211_chan_width to a common format */
+enum chan_width convert2width(int width)
+{
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return CHAN_WIDTH_20_NOHT;
+ case NL80211_CHAN_WIDTH_20:
+ return CHAN_WIDTH_20;
+ case NL80211_CHAN_WIDTH_40:
+ return CHAN_WIDTH_40;
+ case NL80211_CHAN_WIDTH_80:
+ return CHAN_WIDTH_80;
+ case NL80211_CHAN_WIDTH_80P80:
+ return CHAN_WIDTH_80P80;
+ case NL80211_CHAN_WIDTH_160:
+ return CHAN_WIDTH_160;
+ }
+ return CHAN_WIDTH_UNKNOWN;
+}
+
+
+int is_ap_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_AP ||
+ nlmode == NL80211_IFTYPE_P2P_GO;
+}
+
+
+int is_sta_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_STATION ||
+ nlmode == NL80211_IFTYPE_P2P_CLIENT;
+}
+
+
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+ nlmode == NL80211_IFTYPE_P2P_GO;
+}
+
+
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex)
+{
+ struct i802_bss *bss;
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (bss->ifindex == ifindex)
+ return bss;
+ }
+
+ return NULL;
+}
+
+
+static int is_mesh_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_MESH_POINT;
+}
+
+
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->associated)
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ drv->associated = 0;
+ os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->first_bss->freq = 0;
+}
+
+
+/* nl80211 code */
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *err = arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+
+struct nl80211_ack_ext_arg {
+ int *err;
+ void *ext_data;
+};
+
+
+static int ack_handler_cookie(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_ack_ext_arg *ext_arg = arg;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ u64 *cookie = ext_arg->ext_data;
+ struct nlattr *attrs;
+ size_t ack_len, attr_len;
+
+ *ext_arg->err = 0;
+ ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
+ sizeof(struct nlmsghdr);
+ attrs = (struct nlattr *)
+ ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
+ sizeof(int));
+ if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
+ return NL_STOP;
+
+ attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
+
+ if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
+ return NL_STOP;
+
+ nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
+ if (tb[NLMSGERR_ATTR_COOKIE])
+ *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
+
+ return NL_STOP;
+}
+
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
+ int len = nlh->nlmsg_len;
+ struct nlattr *attrs;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ int *ret = arg;
+ int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
+
+ *ret = err->error;
+
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ return NL_SKIP;
+
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ ack_len += err->msg.nlmsg_len - sizeof(*nlh);
+
+ if (len <= ack_len)
+ return NL_STOP;
+
+ attrs = (void *) ((unsigned char *) nlh + ack_len);
+ len -= ack_len;
+
+ nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
+ if (tb[NLMSGERR_ATTR_MSG]) {
+ len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
+ nla_len(tb[NLMSGERR_ATTR_MSG]));
+ wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
+ len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+ }
+
+ return NL_SKIP;
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+ /*
+ * Clear nlmsg data, e.g., to make sure key material is not left in
+ * heap memory for unnecessarily long time.
+ */
+ if (msg) {
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ void *data = nlmsg_data(hdr);
+ /*
+ * This would use nlmsg_datalen() or the older nlmsg_len() if
+ * only libnl were to maintain a stable API.. Neither will work
+ * with all released versions, so just calculate the length
+ * here.
+ */
+ int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+ os_memset(data, 0, len);
+ }
+}
+
+
+static int send_and_recv(struct nl80211_global *global,
+ struct nl_sock *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
+{
+ struct nl_cb *cb;
+ int err = -ENOMEM, opt;
+
+ if (!msg)
+ return -ENOMEM;
+
+ cb = nl_cb_clone(global->nl_cb);
+ if (!cb)
+ goto out;
+
+ /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
+ opt = 1;
+ setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_EXT_ACK, &opt, sizeof(opt));
+
+ /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
+ opt = 1;
+ setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_CAP_ACK, &opt, sizeof(opt));
+
+ err = nl_send_auto_complete(nl_handle, msg);
+ if (err < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: nl_send_auto_complete() failed: %s",
+ nl_geterror(err));
+ /* Need to convert libnl error code to an errno value. For now,
+ * just hardcode this to EBADF; the real error reason is shown
+ * in that error print above. */
+ err = -EBADF;
+ goto out;
+ }
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ if (ack_handler_custom) {
+ struct nl80211_ack_ext_arg *ext_arg = ack_data;
+
+ ext_arg->err = &err;
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
+ ack_handler_custom, ack_data);
+ } else {
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ }
+
+ if (valid_handler)
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ valid_handler, valid_data);
+
+ while (err > 0) {
+ int res = nl_recvmsgs(nl_handle, cb);
+
+ if (res == -NLE_DUMP_INTR) {
+ /* Most likely one of the nl80211 dump routines hit a
+ * case where internal results changed while the dump
+ * was being sent. The most common known case for this
+ * is scan results fetching while associated were every
+ * received Beacon frame from the AP may end up
+ * incrementing bss_generation. This
+ * NL80211_CMD_GET_SCAN case tries again in the caller;
+ * other cases (of which there are no known common ones)
+ * will stop and return an error. */
+ wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
+ nl_geterror(res));
+ err = -EAGAIN;
+ } else if (res < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: %s->nl_recvmsgs failed: %d (%s)",
+ __func__, res, nl_geterror(res));
+ }
+ }
+ out:
+ nl_cb_put(cb);
+ /* Always clear the message as it can potentially contain keys */
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return err;
+}
+
+
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
+{
+ return send_and_recv(drv->global, drv->global->nl, msg,
+ valid_handler, valid_data,
+ ack_handler_custom, ack_data);
+}
+
+
+/* Use this method to mark that it is necessary to own the connection/interface
+ * for this operation.
+ * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
+ * set_owner can be used to mark this socket for receiving control port frames.
+ */
+static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ struct nl_sock *handle, int set_owner,
+ int (*valid_handler)(struct nl_msg *,
+ void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *,
+ void *),
+ void *ack_data)
+{
+ if (!msg)
+ return -ENOMEM;
+
+ /* Control port over nl80211 needs the flags and attributes below.
+ *
+ * The Linux kernel has initial checks for them (in nl80211.c) like:
+ * validate_pae_over_nl80211(...)
+ * or final checks like:
+ * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
+ *
+ * Final operations (e.g., disassociate) don't need to set these
+ * attributes, but they have to be performed on the socket, which has
+ * the connection owner property set in the kernel.
+ */
+ if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
+ handle && set_owner &&
+ (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+ nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
+ nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
+ return -1;
+
+ return send_and_recv(drv->global, handle ? handle : drv->global->nl,
+ msg, valid_handler, valid_data,
+ ack_handler_custom, ack_data);
+}
+
+
+static int
+send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, struct i802_bss *bss,
+ int set_owner)
+{
+ struct nl_sock *nl_connect = get_connect_handle(bss);
+
+ if (nl_connect)
+ return send_and_recv_msgs_owner(drv, msg, nl_connect, set_owner,
+ process_bss_event, bss, NULL,
+ NULL);
+ else
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+struct nl_sock * get_connect_handle(struct i802_bss *bss)
+{
+ if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
+ bss->use_nl_connect)
+ return bss->nl_connect;
+
+ return NULL;
+}
+
+
+struct family_data {
+ const char *group;
+ int id;
+};
+
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+ struct family_data *res = arg;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *mcgrp;
+ int i;
+
+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[CTRL_ATTR_MCAST_GROUPS])
+ return NL_SKIP;
+
+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
+ !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
+ os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
+ res->group,
+ nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
+ continue;
+ res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ };
+
+ return NL_SKIP;
+}
+
+
+static int nl_get_multicast_id(struct nl80211_global *global,
+ const char *family, const char *group)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct family_data res = { group, -ENOENT };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+ if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0) ||
+ nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv(global, global->nl, msg, family_handler, &res,
+ NULL, NULL);
+ if (ret == 0)
+ ret = res.id;
+ return ret;
+}
+
+
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd)
+{
+ if (TEST_FAIL())
+ return NULL;
+ return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
+ 0, flags, cmd, 0);
+}
+
+
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+ if (bss->wdev_id_set)
+ return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+ return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+}
+
+
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
+ nl80211_set_iface_id(msg, bss) < 0) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static struct nl_msg *
+nl80211_ifindex_msg_build(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int ifindex, int flags,
+ uint8_t cmd)
+{
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(drv, msg, flags, cmd) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static struct nl_msg *
+nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
+ int flags, uint8_t cmd)
+{
+ return nl80211_ifindex_msg_build(drv, nlmsg_alloc(), ifindex, flags,
+ cmd);
+}
+
+
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd)
+{
+ return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
+}
+
+
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
+}
+
+
+struct wiphy_idx_data {
+ int wiphy_idx;
+ enum nl80211_iftype nlmode;
+ u8 *macaddr;
+ u8 use_4addr;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_idx_data *info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_WIPHY])
+ info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+ if (tb[NL80211_ATTR_IFTYPE])
+ info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+ if (tb[NL80211_ATTR_MAC] && info->macaddr)
+ os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+
+ if (tb[NL80211_ATTR_4ADDR])
+ info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .wiphy_idx = -1,
+ .macaddr = NULL,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
+
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
+ return data.wiphy_idx;
+ return -1;
+}
+
+
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .nlmode = NL80211_IFTYPE_UNSPECIFIED,
+ .macaddr = NULL,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return NL80211_IFTYPE_UNSPECIFIED;
+
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
+ return data.nlmode;
+ return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .macaddr = bss->addr,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
+
+ return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL);
+}
+
+
+static int nl80211_get_4addr(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .use_4addr = 0,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
+ send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL))
+ return -1;
+ return data.use_4addr;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+ struct nl80211_wiphy_data *w)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+ "failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+ struct nl80211_wiphy_data *w = eloop_ctx;
+ int res;
+
+ wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
+
+ res = nl_recvmsgs(handle, w->nl_cb);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_wiphy_data *w = arg;
+ struct wpa_driver_nl80211_data *drv;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ union wpa_event_data event;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (gnlh->cmd != NL80211_CMD_FRAME) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+ gnlh->cmd);
+ return NL_SKIP;
+ }
+
+ if (!tb[NL80211_ATTR_FRAME])
+ return NL_SKIP;
+
+ dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+ wiphy_list) {
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+ event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+ static DEFINE_DL_LIST(nl80211_wiphys);
+ struct nl80211_wiphy_data *w;
+ int wiphy_idx, found = 0;
+ struct i802_bss *tmp_bss;
+ u8 channel;
+
+ if (bss->wiphy_data != NULL)
+ return bss->wiphy_data;
+
+ wiphy_idx = nl80211_get_wiphy_index(bss);
+
+ dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+ if (w->wiphy_idx == wiphy_idx)
+ goto add;
+ }
+
+ /* alloc new one */
+ w = os_zalloc(sizeof(*w));
+ if (w == NULL)
+ return NULL;
+ w->wiphy_idx = wiphy_idx;
+ dl_list_init(&w->bsss);
+ dl_list_init(&w->drvs);
+
+ /* Beacon frames not supported in IEEE 802.11ad */
+ if (ieee80211_freq_to_chan(bss->freq, &channel) !=
+ HOSTAPD_MODE_IEEE80211AD) {
+ w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!w->nl_cb) {
+ os_free(w);
+ return NULL;
+ }
+ nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_beacon_event, w);
+
+ w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+ "wiphy beacons");
+ if (w->nl_beacons == NULL) {
+ os_free(w);
+ return NULL;
+ }
+
+ if (nl80211_register_beacons(bss->drv, w)) {
+ nl_destroy_handles(&w->nl_beacons);
+ os_free(w);
+ return NULL;
+ }
+
+ nl80211_register_eloop_read(&w->nl_beacons,
+ nl80211_recv_beacons, w, 0);
+ }
+
+ dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+ /* drv entry for this bss already there? */
+ dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+ if (tmp_bss->drv == bss->drv) {
+ found = 1;
+ break;
+ }
+ }
+ /* if not add it */
+ if (!found)
+ dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+ dl_list_add(&w->bsss, &bss->wiphy_list);
+ bss->wiphy_data = w;
+ return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+ struct nl80211_wiphy_data *w = bss->wiphy_data;
+ struct i802_bss *tmp_bss;
+ int found = 0;
+
+ if (w == NULL)
+ return;
+ bss->wiphy_data = NULL;
+ dl_list_del(&bss->wiphy_list);
+
+ /* still any for this drv present? */
+ dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+ if (tmp_bss->drv == bss->drv) {
+ found = 1;
+ break;
+ }
+ }
+ /* if not remove it */
+ if (!found)
+ dl_list_del(&bss->drv->wiphy_list);
+
+ if (!dl_list_empty(&w->bsss))
+ return;
+
+ if (w->nl_beacons)
+ nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
+
+ nl_cb_put(w->nl_cb);
+ dl_list_del(&w->list);
+ os_free(w);
+}
+
+
+static unsigned int nl80211_get_ifindex(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ return drv->ifindex;
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!drv->associated)
+ return -1;
+ os_memcpy(bssid, drv->bssid, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!drv->associated)
+ return -1;
+ os_memcpy(ssid, drv->ssid, drv->ssid_len);
+ return drv->ssid_len;
+}
+
+
+static void wpa_driver_nl80211_event_newlink(
+ struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+ int ifindex, const char *ifname)
+{
+ union wpa_event_data event;
+
+ if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+ if (if_nametoindex(drv->first_bss->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
+ drv->first_bss->ifname);
+ return;
+ }
+ if (!drv->if_removed)
+ return;
+ wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
+ drv->first_bss->ifname);
+ drv->if_removed = 0;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.interface_status.ifindex = ifindex;
+ os_strlcpy(event.interface_status.ifname, ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ if (drv)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ else
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+}
+
+
+static void wpa_driver_nl80211_event_dellink(
+ struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+ int ifindex, const char *ifname)
+{
+ union wpa_event_data event;
+
+ if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+ if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
+ ifname);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
+ ifname);
+ drv->if_removed = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
+ ifname);
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.interface_status.ifindex = ifindex;
+ os_strlcpy(event.interface_status.ifname, ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ if (drv)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+ else
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+}
+
+
+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len)
+{
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len,
+ drv->first_bss->ifname) == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex, u8 *buf, size_t len)
+{
+ if (drv->ifindex == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+ nl80211_check_global(drv->global);
+ wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
+ "interface");
+ if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
+ return -1;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
+ int *init_failed)
+{
+ struct wpa_driver_nl80211_data *drv;
+ int res;
+
+ if (init_failed)
+ *init_failed = 0;
+ dl_list_for_each(drv, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Found matching own interface, but failed to complete reinitialization");
+ if (init_failed)
+ *init_failed = 1;
+ return drv;
+ }
+ if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
+ return drv;
+ }
+ return NULL;
+}
+
+
+static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int notify)
+{
+ struct i802_bss *bss;
+ u8 addr[ETH_ALEN];
+
+ bss = get_bss_ifindex(drv, ifindex);
+ if (bss &&
+ linux_get_ifhwaddr(drv->global->ioctl_sock,
+ bss->ifname, addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: %s: failed to re-read MAC address",
+ bss->ifname);
+ } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Own MAC address on ifindex %d (%s) changed from "
+ MACSTR " to " MACSTR,
+ ifindex, bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(addr));
+ os_memcpy(bss->addr, addr, ETH_ALEN);
+ if (notify)
+ wpa_supplicant_event(drv->ctx,
+ EVENT_INTERFACE_MAC_CHANGED, NULL);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
+ struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct nl80211_global *global = ctx;
+ struct wpa_driver_nl80211_data *drv;
+ int attrlen;
+ struct rtattr *attr;
+ u32 brid = 0;
+ char namebuf[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 1];
+ char extra[100], *pos, *end;
+ int init_failed;
+
+ extra[0] = '\0';
+ pos = extra;
+ end = pos + sizeof(extra);
+ ifname[0] = '\0';
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+ while (RTA_OK(attr, attrlen)) {
+ switch (attr->rta_type) {
+ case IFLA_IFNAME:
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
+ break;
+ os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
+ ifname[RTA_PAYLOAD(attr)] = '\0';
+ break;
+ case IFLA_MASTER:
+ brid = nla_get_u32((struct nlattr *) attr);
+ pos += os_snprintf(pos, end - pos, " master=%u", brid);
+ break;
+ case IFLA_WIRELESS:
+ pos += os_snprintf(pos, end - pos, " wext");
+ break;
+ case IFLA_OPERSTATE:
+ pos += os_snprintf(pos, end - pos, " operstate=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ case IFLA_LINKMODE:
+ pos += os_snprintf(pos, end - pos, " linkmode=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ extra[sizeof(extra) - 1] = '\0';
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
+ if (!drv)
+ goto event_newlink;
+ if (init_failed)
+ return; /* do not update interface state */
+
+ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+ namebuf[0] = '\0';
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+ "event since interface %s is up", namebuf);
+ drv->ignore_if_down_event = 0;
+ /* Re-read MAC address as it may have changed */
+ nl80211_refresh_mac(drv, ifi->ifi_index, 1);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
+ namebuf, ifname);
+ if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface down",
+ drv->first_bss->ifname);
+ } else if (drv->ignore_if_down_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+ "event generated by mode change");
+ drv->ignore_if_down_event = 0;
+ } else {
+ drv->if_disabled = 1;
+ wpa_supplicant_event(drv->ctx,
+ EVENT_INTERFACE_DISABLED, NULL);
+
+ /*
+ * Try to get drv again, since it may be removed as
+ * part of the EVENT_INTERFACE_DISABLED handling for
+ * dynamic interfaces
+ */
+ drv = nl80211_find_drv(global, ifi->ifi_index,
+ buf, len, NULL);
+ if (!drv)
+ return;
+ }
+ }
+
+ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+ namebuf[0] = '\0';
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s is down",
+ namebuf);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
+ namebuf, ifname);
+ if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface up",
+ drv->first_bss->ifname);
+ } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s does not exist",
+ drv->first_bss->ifname);
+ } else if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s is marked "
+ "removed", drv->first_bss->ifname);
+ } else {
+ /* Re-read MAC address as it may have changed */
+ nl80211_refresh_mac(drv, ifi->ifi_index, 0);
+
+ drv->if_disabled = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ }
+
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
+ }
+
+event_newlink:
+ if (ifname[0])
+ wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
+ ifname);
+
+ if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
+ struct i802_bss *bss;
+
+ /* device has been added to bridge */
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
+ brid, namebuf);
+ add_ifidx(drv, brid, ifi->ifi_index);
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (os_strcmp(ifname, bss->ifname) == 0) {
+ os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
+ break;
+ }
+ }
+ }
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
+ struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct nl80211_global *global = ctx;
+ struct wpa_driver_nl80211_data *drv;
+ int attrlen;
+ struct rtattr *attr;
+ u32 brid = 0;
+ char ifname[IFNAMSIZ + 1];
+ char extra[100], *pos, *end;
+
+ extra[0] = '\0';
+ pos = extra;
+ end = pos + sizeof(extra);
+ ifname[0] = '\0';
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+ while (RTA_OK(attr, attrlen)) {
+ switch (attr->rta_type) {
+ case IFLA_IFNAME:
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
+ break;
+ os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
+ ifname[RTA_PAYLOAD(attr)] = '\0';
+ break;
+ case IFLA_MASTER:
+ brid = nla_get_u32((struct nlattr *) attr);
+ pos += os_snprintf(pos, end - pos, " master=%u", brid);
+ break;
+ case IFLA_OPERSTATE:
+ pos += os_snprintf(pos, end - pos, " operstate=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ case IFLA_LINKMODE:
+ pos += os_snprintf(pos, end - pos, " linkmode=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ extra[sizeof(extra) - 1] = '\0';
+
+ wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
+
+ if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
+ /* device has been removed from bridge */
+ char namebuf[IFNAMSIZ];
+
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove ifindex %u for bridge %s",
+ brid, namebuf);
+ }
+ del_ifidx(drv, brid, ifi->ifi_index);
+ }
+
+ if (ifi->ifi_family != AF_BRIDGE || !brid)
+ wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
+ ifname);
+}
+
+
+struct nl80211_get_assoc_freq_arg {
+ struct wpa_driver_nl80211_data *drv;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+ u8 assoc_ssid[SSID_MAX_LEN];
+ u8 assoc_ssid_len;
+};
+
+static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ };
+ struct nl80211_get_assoc_freq_arg *ctx = arg;
+ enum nl80211_bss_status status;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS] ||
+ nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy) ||
+ !bss[NL80211_BSS_STATUS])
+ return NL_SKIP;
+
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ ctx->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ ctx->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(ctx->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(ctx->assoc_bssid));
+ }
+
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ const u8 *ie, *ssid;
+ size_t ie_len;
+
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
+ ctx->assoc_ssid_len = ssid[1];
+ os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+
+try_again:
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ os_memset(&arg, 0, sizeof(arg));
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg, NULL, NULL);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
+ goto try_again;
+ }
+ }
+ if (ret == 0) {
+ os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
+ return arg.assoc_ssid_len;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+
+try_again:
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ os_memset(&arg, 0, sizeof(arg));
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg, NULL, NULL);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
+ goto try_again;
+ }
+ }
+ if (ret == 0) {
+ unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
+ arg.ibss_freq : arg.assoc_freq;
+ wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
+ "associated BSS from scan results: %u MHz", freq);
+ if (freq)
+ drv->assoc_freq = freq;
+ return drv->assoc_freq;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ return drv->assoc_freq;
+}
+
+
+static int get_link_signal(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
+ 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] = {
+ [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+ [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+ };
+ struct wpa_signal_info *sig_change = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_STA_INFO] ||
+ nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
+ tb[NL80211_ATTR_STA_INFO], policy))
+ return NL_SKIP;
+ if (!sinfo[NL80211_STA_INFO_SIGNAL])
+ return NL_SKIP;
+
+ sig_change->current_signal =
+ (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
+
+ if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+ sig_change->avg_signal =
+ (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+ 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],
+ rate_policy)) {
+ sig_change->current_txrate = 0;
+ } else {
+ if (rinfo[NL80211_RATE_INFO_BITRATE]) {
+ sig_change->current_txrate =
+ nla_get_u16(rinfo[
+ NL80211_RATE_INFO_BITRATE]) * 100;
+ }
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig)
+{
+ struct nl_msg *msg;
+
+ sig->current_signal = -WPA_INVALID_NOISE;
+ sig->current_txrate = 0;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
+}
+
+
+static int get_link_noise(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_signal_info *sig_change = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
+ "attributes!");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ sig_change->frequency)
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ sig_change->current_noise =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change)
+{
+ struct nl_msg *msg;
+
+ sig_change->current_noise = WPA_INVALID_NOISE;
+ sig_change->frequency = drv->assoc_freq;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
+ NULL, NULL);
+}
+
+
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_channel_info *chan_info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
+ chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ chan_info->frequency =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ chan_info->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type ct =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (ct) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_info->sec_channel = -1;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_info->sec_channel = 1;
+ break;
+ default:
+ chan_info->sec_channel = 0;
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ chan_info->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ chan_info->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ if (chan_info->center_frq2) {
+ u8 seg1_idx = 0;
+
+ if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
+ NUM_HOSTAPD_MODES)
+ chan_info->seg1_idx = seg1_idx;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+ void *handle)
+{
+ struct nl_cb *cb = eloop_ctx;
+ int res;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
+
+ res = nl_recvmsgs(handle, cb);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
+}
+
+
+/**
+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
+ * @priv: driver_nl80211 private data
+ * @alpha2_arg: country to which to switch to
+ * Returns: 0 on success, -1 on failure
+ *
+ * This asks nl80211 to set the regulatory domain for given
+ * country ISO / IEC alpha2.
+ */
+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ char alpha2[3];
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ alpha2[0] = alpha2_arg[0];
+ alpha2[1] = alpha2_arg[1];
+ alpha2[2] = '\0';
+
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
+ nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
+ nlmsg_free(msg);
+ return -EINVAL;
+ }
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
+ return -EINVAL;
+ return 0;
+}
+
+
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+ char *alpha2 = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+ return NL_SKIP;
+ }
+ os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ alpha2[0] = '\0';
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
+ NULL, NULL);
+ if (!alpha2[0])
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
+{
+ int ret;
+
+ global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (global->nl_cb == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ return -1;
+ }
+
+ global->nl = nl_create_handle(global->nl_cb, "nl");
+ if (global->nl == NULL)
+ goto err;
+
+ global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+ if (global->nl80211_id < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+ "found");
+ goto err;
+ }
+
+ global->nl_event = nl_create_handle(global->nl_cb, "event");
+ if (global->nl_event == NULL)
+ goto err;
+
+ ret = nl_get_multicast_id(global, "nl80211", "scan");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(global->nl_event, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+ "membership for scan events: %d (%s)",
+ ret, nl_geterror(ret));
+ goto err;
+ }
+
+ ret = nl_get_multicast_id(global, "nl80211", "mlme");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(global->nl_event, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+ "membership for mlme events: %d (%s)",
+ ret, nl_geterror(ret));
+ goto err;
+ }
+
+ ret = nl_get_multicast_id(global, "nl80211", "regulatory");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(global->nl_event, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
+ "membership for regulatory events: %d (%s)",
+ ret, nl_geterror(ret));
+ /* Continue without regulatory events */
+ }
+
+ ret = nl_get_multicast_id(global, "nl80211", "vendor");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(global->nl_event, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
+ "membership for vendor events: %d (%s)",
+ ret, nl_geterror(ret));
+ /* Continue without vendor events */
+ }
+
+ nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_global_event, global);
+
+ nl80211_register_eloop_read(&global->nl_event,
+ wpa_driver_nl80211_event_receive,
+ global->nl_cb, 0);
+
+ return 0;
+
+err:
+ nl_destroy_handles(&global->nl_event);
+ nl_destroy_handles(&global->nl);
+ nl_cb_put(global->nl_cb);
+ global->nl_cb = NULL;
+ return -1;
+}
+
+
+static void nl80211_check_global(struct nl80211_global *global)
+{
+ struct nl_sock *handle;
+ const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
+ int ret;
+ unsigned int i;
+
+ /*
+ * Try to re-add memberships to handle case of cfg80211 getting reloaded
+ * and all registration having been cleared.
+ */
+ handle = (void *) (((intptr_t) global->nl_event) ^
+ ELOOP_SOCKET_INVALID);
+
+ for (i = 0; groups[i]; i++) {
+ ret = nl_get_multicast_id(global, "nl80211", groups[i]);
+ if (ret >= 0)
+ ret = nl_socket_add_membership(handle, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
+ groups[i], ret, nl_geterror(ret));
+ }
+ }
+}
+
+
+static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
+{
+ struct wpa_driver_nl80211_data *drv = ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
+
+ /*
+ * rtnetlink ifdown handler will report interfaces other than the P2P
+ * Device interface as disabled.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
+static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
+{
+ struct wpa_driver_nl80211_data *drv = ctx;
+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
+ if (i802_set_iface_flags(drv->first_bss, 1)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
+ "after rfkill unblock");
+ return;
+ }
+
+ if (is_p2p_net_interface(drv->nlmode))
+ nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+
+ /*
+ * rtnetlink ifup handler will report interfaces other than the P2P
+ * Device interface as enabled.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+}
+
+
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+ void *eloop_ctx,
+ void *handle)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ u8 data[2048];
+ struct msghdr msg;
+ struct iovec entry;
+ u8 control[512];
+ struct cmsghdr *cmsg;
+ int res, found_ee = 0, found_wifi = 0, acked = 0;
+ union wpa_event_data event;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &entry;
+ msg.msg_iovlen = 1;
+ entry.iov_base = data;
+ entry.iov_len = sizeof(data);
+ msg.msg_control = &control;
+ msg.msg_controllen = sizeof(control);
+
+ res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+ /* if error or not fitting 802.3 header, return */
+ if (res < 14)
+ return;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_WIFI_STATUS) {
+ int *ack;
+
+ found_wifi = 1;
+ ack = (void *)CMSG_DATA(cmsg);
+ acked = *ack;
+ }
+
+ if (cmsg->cmsg_level == SOL_PACKET &&
+ cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+ struct sock_extended_err *err =
+ (struct sock_extended_err *)CMSG_DATA(cmsg);
+
+ if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+ found_ee = 1;
+ }
+ }
+
+ if (!found_ee || !found_wifi)
+ return;
+
+ memset(&event, 0, sizeof(event));
+ event.eapol_tx_status.dst = data;
+ event.eapol_tx_status.data = data + 14;
+ event.eapol_tx_status.data_len = res - 14;
+ event.eapol_tx_status.ack = acked;
+ wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_connect_handle(struct i802_bss *bss)
+{
+ if (bss->nl_connect) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect handle already created (nl_connect=%p)",
+ bss->nl_connect);
+ return -1;
+ }
+
+ bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
+ if (!bss->nl_connect)
+ return -1;
+ nl80211_register_eloop_read(&bss->nl_connect,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb, 1);
+ return 0;
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+ bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!bss->nl_cb)
+ return -1;
+
+ nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_bss_event, bss);
+
+ nl80211_init_connect_handle(bss);
+
+ return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+ nl_cb_put(bss->nl_cb);
+ bss->nl_cb = NULL;
+
+ if (bss->nl_connect)
+ nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
+}
+
+
+static void
+wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
+{
+ struct rfkill_config *rcfg;
+
+ if (drv->rfkill)
+ return;
+
+ rcfg = os_zalloc(sizeof(*rcfg));
+ if (!rcfg)
+ return;
+
+ rcfg->ctx = drv;
+
+ /* rfkill uses netdev sysfs for initialization. However, P2P Device is
+ * not associated with a netdev, so use the name of some other interface
+ * sharing the same wiphy as the P2P Device interface.
+ *
+ * Note: This is valid, as a P2P Device interface is always dynamically
+ * created and is created only once another wpa_s interface was added.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ struct nl80211_global *global = drv->global;
+ struct wpa_driver_nl80211_data *tmp1;
+
+ dl_list_for_each(tmp1, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
+ !tmp1->rfkill)
+ continue;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Use (%s) to initialize P2P Device rfkill",
+ tmp1->first_bss->ifname);
+ os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
+ sizeof(rcfg->ifname));
+ break;
+ }
+ } else {
+ os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
+ sizeof(rcfg->ifname));
+ }
+
+ rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
+ rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
+ drv->rfkill = rfkill_init(rcfg);
+ if (!drv->rfkill) {
+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
+ os_free(rcfg);
+ }
+}
+
+
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+ void *global_priv, int hostapd,
+ const u8 *set_addr,
+ const char *driver_params)
+{
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *bss;
+
+ if (global_priv == NULL)
+ return NULL;
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->global = global_priv;
+ drv->ctx = ctx;
+ drv->hostapd = !!hostapd;
+ drv->eapol_sock = -1;
+
+ /*
+ * There is no driver capability flag for this, so assume it is
+ * supported and disable this on first attempt to use if the driver
+ * rejects the command due to missing support.
+ */
+ drv->set_rekey_offload = 1;
+
+ drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
+ drv->if_indices = drv->default_if_indices;
+
+ drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+ if (!drv->first_bss) {
+ os_free(drv);
+ return NULL;
+ }
+ bss = drv->first_bss;
+ bss->drv = drv;
+ bss->ctx = ctx;
+
+ os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+ drv->monitor_ifidx = -1;
+ drv->monitor_sock = -1;
+ drv->eapol_tx_sock = -1;
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+
+ if (nl80211_init_bss(bss))
+ goto failed;
+
+ if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
+ goto failed;
+
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
+ drv->control_port_ap = 1;
+ goto skip_wifi_status;
+ }
+
+ drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (drv->eapol_tx_sock < 0)
+ goto failed;
+
+ if (drv->data_tx_status) {
+ int enabled = 1;
+
+ if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+ &enabled, sizeof(enabled)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: wifi status sockopt failed: %s",
+ strerror(errno));
+ drv->data_tx_status = 0;
+ if (!drv->use_monitor)
+ drv->capa.flags &=
+ ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+ } else {
+ eloop_register_read_sock(
+ drv->eapol_tx_sock,
+ wpa_driver_nl80211_handle_eapol_tx_status,
+ drv, NULL);
+ }
+ }
+skip_wifi_status:
+
+ if (drv->global) {
+ nl80211_check_global(drv->global);
+ dl_list_add(&drv->global->interfaces, &drv->list);
+ drv->in_interface_list = 1;
+ }
+
+ return bss;
+
+failed:
+ wpa_driver_nl80211_deinit(bss);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+ void *global_priv)
+{
+ return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
+ NULL);
+}
+
+
+static int nl80211_register_frame(struct i802_bss *bss,
+ struct nl_sock *nl_handle,
+ u16 type, const u8 *match, size_t match_len,
+ bool multicast)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ char buf[30];
+
+ buf[0] = '\0';
+ wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
+ type, fc2str(type), nl_handle, buf, multicast);
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
+ (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
+ nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
+ "failed (type=%u): ret=%d (%s)",
+ type, ret, strerror(-ret));
+ wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+ match, match_len);
+ }
+ return ret;
+}
+
+
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+ if (bss->nl_mgmt) {
+ wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+ "already on! (nl_mgmt=%p)", bss->nl_mgmt);
+ return -1;
+ }
+
+ bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
+ if (bss->nl_mgmt == NULL)
+ return -1;
+
+ return 0;
+}
+
+
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+ nl80211_register_eloop_read(&bss->nl_mgmt,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb, 0);
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
+ const u8 *match, size_t match_len)
+{
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
+ return nl80211_register_frame(bss, bss->nl_mgmt,
+ type, match, match_len, false);
+}
+
+
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+ int ret = 0;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+ "handle %p", bss->nl_mgmt);
+
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ /* register for any AUTH message */
+ nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
+ } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ /* register for SAE Authentication frames */
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x03\x00", 2, false);
+ }
+
+#ifdef CONFIG_PASN
+ /* register for PASN Authentication frames */
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x07\x00", 2, false))
+ ret = -1;
+#endif /* CONFIG_PASN */
+
+#ifdef CONFIG_INTERWORKING
+ /* QoS Map Configure */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_INTERWORKING */
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
+ /* GAS Initial Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
+ ret = -1;
+ /* GAS Initial Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
+ ret = -1;
+ /* GAS Comeback Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
+ ret = -1;
+ /* GAS Comeback Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
+ ret = -1;
+ /* Protected GAS Initial Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
+ ret = -1;
+ /* Protected GAS Initial Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
+ ret = -1;
+ /* Protected GAS Comeback Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
+ ret = -1;
+ /* Protected GAS Comeback Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
+#ifdef CONFIG_P2P
+ /* P2P Public Action */
+ if (nl80211_register_action_frame(bss,
+ (u8 *) "\x04\x09\x50\x6f\x9a\x09",
+ 6) < 0)
+ ret = -1;
+ /* P2P Action */
+ if (nl80211_register_action_frame(bss,
+ (u8 *) "\x7f\x50\x6f\x9a\x09",
+ 5) < 0)
+ ret = -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP
+ /* DPP Public Action */
+ if (nl80211_register_action_frame(bss,
+ (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
+ 6) < 0)
+ ret = -1;
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_OCV
+ /* SA Query Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_OCV */
+ /* SA Query Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
+ ret = -1;
+#ifdef CONFIG_TDLS
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+ /* TDLS Discovery Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+ 0)
+ 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)
+ ret = -1;
+ else if (!drv->has_driver_key_mgmt) {
+ int i;
+
+ /* Update supported AKMs only if the driver doesn't advertize
+ * any AKM capabilities. */
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+
+ /* Update per interface supported AKMs */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
+ }
+
+ /* WNM - BSS Transition Management Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+ ret = -1;
+ /* WNM-Sleep Mode Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
+ ret = -1;
+#ifdef CONFIG_WNM
+ /* WNM - Collocated Interference Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_HS20
+ /* WNM-Notification */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_HS20 */
+
+ /* WMM-AC ADDTS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
+ ret = -1;
+
+ /* WMM-AC DELTS */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Neighbor Report Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Radio Measurement Request */
+ if (!drv->no_rrm &&
+ nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Link Measurement Request */
+ if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
+ (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
+ ret = -1;
+
+ /* Robust AV MSCS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
+ ret = -1;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+
+ return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
+{
+ int ret = 0;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Subscribe to mgmt frames with mesh handle %p",
+ bss->nl_mgmt);
+
+ /* Auth frames for mesh SAE */
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4),
+ NULL, 0, false) < 0)
+ ret = -1;
+
+ /* Mesh peering open */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
+ ret = -1;
+ /* Mesh peering confirm */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
+ ret = -1;
+ /* Mesh peering close */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
+ ret = -1;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+
+ return ret;
+}
+
+
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
+ ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+ "failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+static int nl80211_action_subscribe_ap(struct i802_bss *bss)
+{
+ int ret = 0;
+
+ /* Public Action frames */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
+ ret = -1;
+ /* RRM Measurement Report */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
+ ret = -1;
+ /* RRM Link Measurement Report */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
+ ret = -1;
+ /* RRM Neighbor Report Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
+ ret = -1;
+ /* FT Action frames */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
+ ret = -1;
+ /* SA Query */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
+ ret = -1;
+ /* Protected Dual of Public Action */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
+ ret = -1;
+ /* WNM */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
+ ret = -1;
+ /* WMM */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
+ ret = -1;
+#ifdef CONFIG_FST
+ /* FST Action frames */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+ ret = -1;
+#endif /* CONFIG_FST */
+ /* Vendor-specific */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+ static const int stypes[] = {
+ WLAN_FC_STYPE_AUTH,
+ WLAN_FC_STYPE_ASSOC_REQ,
+ WLAN_FC_STYPE_REASSOC_REQ,
+ WLAN_FC_STYPE_DISASSOC,
+ WLAN_FC_STYPE_DEAUTH,
+ WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+ /* WLAN_FC_STYPE_BEACON, */
+ };
+ unsigned int i;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+ "handle %p", bss->nl_mgmt);
+
+ for (i = 0; i < ARRAY_SIZE(stypes); i++) {
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (stypes[i] << 4),
+ NULL, 0, false) < 0) {
+ goto out_err;
+ }
+ }
+
+ if (nl80211_action_subscribe_ap(bss))
+ goto out_err;
+
+ if (nl80211_register_spurious_class3(bss))
+ goto out_err;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+ return 0;
+
+out_err:
+ nl_destroy_handles(&bss->nl_mgmt);
+ return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+ "handle %p (device SME)", bss->nl_mgmt);
+
+ if (nl80211_action_subscribe_ap(bss))
+ goto out_err;
+
+ if (bss->drv->device_ap_sme) {
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+ /* Register for all Authentication frames */
+ if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
+ false) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
+ }
+
+ nl80211_mgmt_handle_register_eloop(bss);
+ return 0;
+
+out_err:
+ nl_destroy_handles(&bss->nl_mgmt);
+ return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+ if (bss->nl_mgmt == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
+ "(%s)", bss->nl_mgmt, reason);
+ nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
+
+ nl80211_put_wiphy_data_ap(bss);
+}
+
+
+static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+ bss->ifname, (long long unsigned int) bss->wdev_id,
+ strerror(-ret));
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
+ NL80211_CMD_STOP_P2P_DEVICE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+ start ? "Start" : "Stop",
+ bss->ifname, (long long unsigned int) bss->wdev_id,
+ strerror(-ret));
+ return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+ enum nl80211_iftype nlmode;
+
+ nlmode = nl80211_get_ifmode(bss);
+ if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+ bss->ifname, up);
+ }
+
+ /* P2P Device has start/stop which is equivalent */
+ return nl80211_set_p2pdev(bss, up);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
+{
+ /* struct wpa_driver_nl80211_data *drv = arg; */
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA vendor test command response received");
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
+ return NL_SKIP;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Received QCA vendor test command response",
+ nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+ nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
+
+ return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+
+ 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_TEST) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
+ nlmsg_free(msg);
+ return;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
+ NULL, NULL);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA vendor test command returned %d (%s)",
+ ret, strerror(-ret));
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
+static int
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+ const u8 *set_addr, int first,
+ const char *driver_params)
+{
+ struct i802_bss *bss = drv->first_bss;
+ int send_rfkill_event = 0;
+ enum nl80211_iftype nlmode;
+
+ drv->ifindex = if_nametoindex(bss->ifname);
+ bss->ifindex = drv->ifindex;
+ bss->wdev_id = drv->global->if_add_wdevid;
+ bss->wdev_id_set = drv->global->if_add_wdevid_set;
+
+ bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
+ bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
+ drv->global->if_add_wdevid_set = 0;
+
+ if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+ bss->static_ap = 1;
+
+ if (first &&
+ nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
+ linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
+ drv->start_iface_up = 1;
+
+ if (wpa_driver_nl80211_capa(drv))
+ return -1;
+
+ if (driver_params && nl80211_set_param(bss, driver_params) < 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+ bss->ifname, drv->phyname);
+
+ if (set_addr &&
+ (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+ linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ set_addr)))
+ return -1;
+
+ if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_STATION)
+ drv->start_mode_sta = 1;
+
+ if (drv->hostapd || bss->static_ap)
+ nlmode = NL80211_IFTYPE_AP;
+ else if (bss->if_dynamic ||
+ nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
+ nlmode = nl80211_get_ifmode(bss);
+ else
+ nlmode = NL80211_IFTYPE_STATION;
+
+ if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
+ return -1;
+ }
+
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ nl80211_get_macaddr(bss);
+
+ wpa_driver_nl80211_drv_init_rfkill(drv);
+
+ if (!rfkill_is_blocked(drv->rfkill)) {
+ int ret = i802_set_iface_flags(bss, 1);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not set "
+ "interface '%s' UP", bss->ifname);
+ return ret;
+ }
+
+ if (is_p2p_net_interface(nlmode))
+ nl80211_disable_11b_rates(bss->drv,
+ bss->drv->ifindex, 1);
+
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ return ret;
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
+ "interface '%s' due to rfkill", bss->ifname);
+ if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ drv->if_disabled = 1;
+
+ send_rfkill_event = 1;
+ }
+
+ if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
+
+ if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ bss->addr))
+ return -1;
+ os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
+ }
+
+ if (send_rfkill_event) {
+ eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
+ drv, drv->ctx);
+ }
+
+ if (drv->vendor_cmd_test_avail)
+ qca_vendor_test(drv);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+ drv->ifindex);
+ nl80211_put_wiphy_data_ap(bss);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ unsigned int i;
+
+ wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
+ bss->ifname, drv->disabled_11b_rates);
+
+ bss->in_deinit = 1;
+ if (drv->data_tx_status)
+ eloop_unregister_read_sock(drv->eapol_tx_sock);
+ if (drv->eapol_tx_sock >= 0)
+ close(drv->eapol_tx_sock);
+
+ if (bss->nl_preq)
+ wpa_driver_nl80211_probe_req_report(bss, 0);
+ if (bss->added_if_into_bridge) {
+ if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "interface %s from bridge %s: %s",
+ bss->ifname, bss->brname, strerror(errno));
+ }
+
+ if (drv->rtnl_sk)
+ nl_socket_free(drv->rtnl_sk);
+
+ if (bss->added_bridge) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+ 0) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Could not set bridge %s down",
+ bss->brname);
+ if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "bridge %s: %s",
+ bss->brname, strerror(errno));
+ }
+
+ nl80211_remove_monitor_interface(drv);
+
+ if (is_ap_interface(drv->nlmode))
+ wpa_driver_nl80211_del_beacon(bss);
+
+ if (drv->eapol_sock >= 0) {
+ eloop_unregister_read_sock(drv->eapol_sock);
+ close(drv->eapol_sock);
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ os_free(drv->if_indices);
+
+ if (drv->disabled_11b_rates)
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+ IF_OPER_UP);
+ eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
+ rfkill_deinit(drv->rfkill);
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+ if (!drv->start_iface_up)
+ (void) i802_set_iface_flags(bss, 0);
+
+ if (drv->addr_changed) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set interface down to restore permanent MAC address");
+ }
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ drv->perm_addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore permanent MAC address");
+ }
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ if (drv->start_mode_sta)
+ wpa_driver_nl80211_set_mode(bss,
+ NL80211_IFTYPE_STATION);
+ nl80211_mgmt_unsubscribe(bss, "deinit");
+ } else {
+ nl80211_mgmt_unsubscribe(bss, "deinit");
+ nl80211_del_p2pdev(bss);
+ }
+
+ nl80211_destroy_bss(drv->first_bss);
+
+ os_free(drv->filter_ssids);
+
+ os_free(drv->auth_ie);
+ os_free(drv->auth_data);
+
+ if (drv->in_interface_list)
+ dl_list_del(&drv->list);
+
+ os_free(drv->extended_capa);
+ os_free(drv->extended_capa_mask);
+ for (i = 0; i < drv->num_iface_ext_capa; i++) {
+ os_free(drv->iface_ext_capa[i].ext_capa);
+ os_free(drv->iface_ext_capa[i].ext_capa_mask);
+ }
+ os_free(drv->first_bss);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ os_free(drv->pending_roam_data);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ os_free(drv);
+}
+
+
+static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
+{
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ return RSN_CIPHER_SUITE_WEP40;
+ return RSN_CIPHER_SUITE_WEP104;
+ case WPA_ALG_TKIP:
+ return RSN_CIPHER_SUITE_TKIP;
+ case WPA_ALG_CCMP:
+ return RSN_CIPHER_SUITE_CCMP;
+ case WPA_ALG_GCMP:
+ return RSN_CIPHER_SUITE_GCMP;
+ case WPA_ALG_CCMP_256:
+ return RSN_CIPHER_SUITE_CCMP_256;
+ case WPA_ALG_GCMP_256:
+ return RSN_CIPHER_SUITE_GCMP_256;
+ case WPA_ALG_BIP_CMAC_128:
+ return RSN_CIPHER_SUITE_AES_128_CMAC;
+ case WPA_ALG_BIP_GMAC_128:
+ return RSN_CIPHER_SUITE_BIP_GMAC_128;
+ case WPA_ALG_BIP_GMAC_256:
+ return RSN_CIPHER_SUITE_BIP_GMAC_256;
+ case WPA_ALG_BIP_CMAC_256:
+ return RSN_CIPHER_SUITE_BIP_CMAC_256;
+ case WPA_ALG_SMS4:
+ return RSN_CIPHER_SUITE_SMS4;
+ case WPA_ALG_KRK:
+ return RSN_CIPHER_SUITE_KRK;
+ case WPA_ALG_NONE:
+ wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
+ alg);
+ return 0;
+ }
+
+ wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
+ alg);
+ return 0;
+}
+
+
+static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP_256:
+ return RSN_CIPHER_SUITE_CCMP_256;
+ case WPA_CIPHER_GCMP_256:
+ return RSN_CIPHER_SUITE_GCMP_256;
+ case WPA_CIPHER_CCMP:
+ return RSN_CIPHER_SUITE_CCMP;
+ case WPA_CIPHER_GCMP:
+ return RSN_CIPHER_SUITE_GCMP;
+ case WPA_CIPHER_TKIP:
+ return RSN_CIPHER_SUITE_TKIP;
+ case WPA_CIPHER_WEP104:
+ return RSN_CIPHER_SUITE_WEP104;
+ case WPA_CIPHER_WEP40:
+ return RSN_CIPHER_SUITE_WEP40;
+ case WPA_CIPHER_GTK_NOT_USED:
+ return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
+ }
+
+ return 0;
+}
+
+
+static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
+ int max_suites)
+{
+ int num_suites = 0;
+
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
+ suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
+ if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
+
+ return num_suites;
+}
+
+
+static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
+ int max_suites)
+{
+ int num_suites = 0;
+
+#define __AKM(a, b) \
+ if (num_suites < max_suites && \
+ (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
+ suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
+ __AKM(IEEE8021X, UNSPEC_802_1X);
+ __AKM(PSK, PSK_OVER_802_1X);
+ __AKM(FT_IEEE8021X, FT_802_1X);
+ __AKM(FT_PSK, FT_PSK);
+ __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
+ __AKM(PSK_SHA256, PSK_SHA256);
+ __AKM(SAE, SAE);
+ __AKM(FT_SAE, FT_SAE);
+ __AKM(CCKM, CCKM);
+ __AKM(OSEN, OSEN);
+ __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
+ __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
+ __AKM(FILS_SHA256, FILS_SHA256);
+ __AKM(FILS_SHA384, FILS_SHA384);
+ __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
+ __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
+ __AKM(OWE, OWE);
+ __AKM(DPP, DPP);
+ __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
+#undef __AKM
+
+ return num_suites;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
+ return 0;
+
+ 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_KEY_MGMT_SET_KEY) ||
+ nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -1;
+ }
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management set key failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
+static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len,
+ const u8 *addr)
+{
+ struct nl_msg *msg = NULL;
+ int ret;
+
+ /*
+ * If the authenticator address is not set, assume it is
+ * the current BSSID.
+ */
+ if (!addr && drv->associated)
+ addr = drv->bssid;
+ else if (!addr)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
+ MAC2STR(addr));
+ wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
+ struct wpa_driver_set_key_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifindex;
+ struct nl_msg *msg;
+ struct nl_msg *key_msg;
+ int ret;
+ int skip_set_key = 1;
+ const char *ifname = params->ifname;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
+ int vlan_id = params->vlan_id;
+ enum key_flag key_flag = params->key_flag;
+
+ /* Ignore for P2P Device */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+
+ ifindex = if_nametoindex(ifname);
+ wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
+ "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
+ __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len, key_flag);
+
+ if (check_key_flag(key_flag)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if ((key_flag & KEY_FLAG_PMK) &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
+ __func__);
+ ret = issue_key_mgmt_set_key(drv, key, key_len);
+ return ret;
+ }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+ if (key_flag & KEY_FLAG_PMK) {
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
+ return nl80211_set_pmk(drv, key, key_len, addr);
+ /* The driver does not have any offload mechanism for PMK, so
+ * there is no need to configure this key. */
+ return 0;
+ }
+
+ ret = -ENOBUFS;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return ret;
+
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: SET_KEY (pairwise RX/TX modify)");
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg)
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
+ __func__);
+ ret = -EINVAL;
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
+ if (!msg)
+ goto fail2;
+ } else {
+ u32 suite;
+
+ suite = wpa_alg_to_cipher_suite(alg, key_len);
+ if (!suite) {
+ ret = -EINVAL;
+ goto fail2;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
+ if (!msg)
+ goto fail2;
+ if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
+ nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
+
+ if (seq && seq_len) {
+ if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
+ seq, seq_len);
+ }
+ }
+
+ if (addr && !is_broadcast_ether_addr(addr)) {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
+
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX ||
+ (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ if (nla_put_u8(key_msg, NL80211_KEY_MODE,
+ key_flag == KEY_FLAG_PAIRWISE_RX ?
+ NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
+ goto fail;
+ } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
+ KEY_FLAG_GROUP_RX) {
+ wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
+ if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
+ NL80211_KEYTYPE_GROUP))
+ goto fail;
+ } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
+ wpa_printf(MSG_DEBUG,
+ " key_flag missing PAIRWISE when setting a pairwise key");
+ ret = -EINVAL;
+ goto fail;
+ } else if (alg == WPA_ALG_WEP &&
+ (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
+ wpa_printf(MSG_DEBUG, " unicast WEP key");
+ skip_set_key = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, " pairwise key");
+ }
+ } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
+ !(key_flag & KEY_FLAG_GROUP)) {
+ wpa_printf(MSG_DEBUG,
+ " invalid key_flag for a broadcast key");
+ ret = -EINVAL;
+ goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG, " broadcast key");
+ if (key_flag & KEY_FLAG_DEFAULT)
+ skip_set_key = 0;
+ }
+ if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
+ ret = 0;
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
+ ret, strerror(-ret));
+
+ /*
+ * If we failed or don't need to set the key as default (below),
+ * we're done here.
+ */
+ if (ret || skip_set_key)
+ return ret;
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
+
+ ret = -ENOBUFS;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return ret;
+
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg)
+ goto fail2;
+ if (!key_msg ||
+ nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_flag(key_msg, wpa_alg_bip(alg) ?
+ (key_idx == 6 || key_idx == 7 ?
+ NL80211_KEY_DEFAULT_BEACON :
+ NL80211_KEY_DEFAULT_MGMT) :
+ NL80211_KEY_DEFAULT))
+ goto fail;
+ if (addr && is_broadcast_ether_addr(addr)) {
+ struct nlattr *types;
+
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
+ if (!types ||
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ goto fail;
+ nla_nest_end(key_msg, types);
+ } else if (addr) {
+ struct nlattr *types;
+
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
+ if (!types ||
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ goto fail;
+ nla_nest_end(key_msg, types);
+ }
+
+ if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
+ vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: set_key default failed; err=%d %s",
+ ret, strerror(-ret));
+ return ret;
+
+fail:
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+fail2:
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ return ret;
+}
+
+
+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
+ int key_idx, int defkey,
+ const u8 *seq, size_t seq_len,
+ 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 && wpa_alg_bip(alg)) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
+ return -1;
+ } else if (defkey) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
+ return -1;
+ }
+
+ if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
+ 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))
+ return -1;
+
+ nla_nest_end(msg, key_attr);
+
+ return 0;
+}
+
+
+static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
+{
+ int i, privacy = 0;
+ struct nlattr *nl_keys, *nl_key;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ privacy = 1;
+ break;
+ }
+ if (params->wps == WPS_MODE_PRIVACY)
+ privacy = 1;
+ if (params->pairwise_suite &&
+ params->pairwise_suite != WPA_CIPHER_NONE)
+ privacy = 1;
+
+ if (!privacy)
+ return 0;
+
+ if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ return -ENOBUFS;
+
+ nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
+ if (!nl_keys)
+ return -ENOBUFS;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+
+ nl_key = nla_nest_start(msg, i);
+ if (!nl_key ||
+ nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER,
+ params->wep_key_len[i] == 5 ?
+ RSN_CIPHER_SUITE_WEP40 :
+ RSN_CIPHER_SUITE_WEP104) ||
+ nla_put_u8(msg, NL80211_KEY_IDX, i) ||
+ (i == params->wep_tx_keyidx &&
+ nla_put_flag(msg, NL80211_KEY_DEFAULT)))
+ return -ENOBUFS;
+
+ nla_nest_end(msg, nl_key);
+ }
+ nla_nest_end(msg, nl_keys);
+
+ return 0;
+}
+
+
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change,
+ struct i802_bss *bss)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct nl_sock *nl_connect = get_connect_handle(bss);
+
+ if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ (local_state_change &&
+ nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (nl_connect)
+ ret = send_and_recv(drv->global, nl_connect, msg,
+ process_bss_event, bss, NULL, NULL);
+ else
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed: reason=%u ret=%d (%s)",
+ reason_code, ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+ u16 reason_code,
+ struct i802_bss *bss)
+{
+ int ret;
+ int drv_associated = drv->associated;
+
+ wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
+ nl80211_mark_disconnected(drv);
+ /* Disconnect command doesn't need BSSID - it uses cached value */
+ ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+ reason_code, 0, bss);
+ /*
+ * For locally generated disconnect, supplicant already generates a
+ * DEAUTH event, so ignore the event from NL80211.
+ */
+ drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+ const u8 *addr, u16 reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
+ int drv_associated = drv->associated;
+
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ nl80211_mark_disconnected(drv);
+ return nl80211_leave_ibss(drv, 1);
+ }
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ return wpa_driver_nl80211_disconnect(drv, reason_code, bss);
+ }
+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
+ __func__, MAC2STR(addr), reason_code);
+ nl80211_mark_disconnected(drv);
+ ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
+ reason_code, 0, bss);
+ /*
+ * For locally generated deauthenticate, supplicant already generates a
+ * DEAUTH event, so ignore the event from NL80211.
+ */
+ drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+
+ return ret;
+}
+
+
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_auth_params *params)
+{
+ int i;
+
+ drv->auth_freq = params->freq;
+ drv->auth_alg = params->auth_alg;
+ drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+ drv->auth_local_state_change = params->local_state_change;
+ drv->auth_p2p = params->p2p;
+
+ if (params->bssid)
+ os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+ else
+ os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+ if (params->ssid) {
+ os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+ drv->auth_ssid_len = params->ssid_len;
+ } else
+ drv->auth_ssid_len = 0;
+
+
+ os_free(drv->auth_ie);
+ drv->auth_ie = NULL;
+ drv->auth_ie_len = 0;
+ if (params->ie) {
+ drv->auth_ie = os_malloc(params->ie_len);
+ if (drv->auth_ie) {
+ os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+ drv->auth_ie_len = params->ie_len;
+ }
+ }
+
+ os_free(drv->auth_data);
+ drv->auth_data = NULL;
+ drv->auth_data_len = 0;
+ if (params->auth_data) {
+ drv->auth_data = os_memdup(params->auth_data,
+ params->auth_data_len);
+ if (drv->auth_data)
+ drv->auth_data_len = params->auth_data_len;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (params->wep_key[i] && params->wep_key_len[i] &&
+ params->wep_key_len[i] <= 16) {
+ os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+ params->wep_key_len[i]);
+ drv->auth_wep_key_len[i] = params->wep_key_len[i];
+ } else
+ drv->auth_wep_key_len[i] = 0;
+ }
+}
+
+
+static void nl80211_unmask_11b_rates(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
+ return;
+
+ /*
+ * Looks like we failed to unmask 11b rates previously. This could
+ * happen, e.g., if the interface was down at the point in time when a
+ * P2P group was terminated.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
+ bss->ifname);
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+}
+
+
+static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
+{
+ if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
+ return NL80211_AUTHTYPE_OPEN_SYSTEM;
+ if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
+ return NL80211_AUTHTYPE_SHARED_KEY;
+ if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
+ return NL80211_AUTHTYPE_NETWORK_EAP;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FT)
+ return NL80211_AUTHTYPE_FT;
+ if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
+ return NL80211_AUTHTYPE_SAE;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
+ return NL80211_AUTHTYPE_FILS_SK;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
+ return NL80211_AUTHTYPE_FILS_SK_PFS;
+
+ return NL80211_AUTHTYPE_MAX;
+}
+
+
+static int wpa_driver_nl80211_authenticate(
+ struct i802_bss *bss, struct wpa_driver_auth_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, i;
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ enum nl80211_iftype nlmode;
+ int count = 0;
+ int is_retry;
+ struct wpa_driver_set_key_params p;
+
+ nl80211_unmask_11b_rates(bss);
+
+ is_retry = drv->retry_auth;
+ drv->retry_auth = 0;
+ drv->ignore_deauth_event = 0;
+
+ nl80211_mark_disconnected(drv);
+ os_memset(drv->auth_bssid, 0, ETH_ALEN);
+ if (params->bssid)
+ os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+ else
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
+ /* FIX: IBSS mode */
+ nlmode = params->p2p ?
+ NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+ if (drv->nlmode != nlmode &&
+ wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
+ return -1;
+
+retry:
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
+ drv->ifindex);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
+ if (!msg)
+ goto fail;
+
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = bss->ifname;
+ p.alg = WPA_ALG_WEP;
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ p.key_idx = i;
+ p.set_tx = i == params->wep_tx_keyidx;
+ p.key = params->wep_key[i];
+ p.key_len = params->wep_key_len[i];
+ p.key_flag = i == params->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX;
+ wpa_driver_nl80211_set_key(bss, &p);
+ if (params->wep_tx_keyidx != i)
+ continue;
+ if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
+ params->wep_key[i], params->wep_key_len[i]))
+ goto fail;
+ }
+
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
+ }
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+ goto fail;
+ }
+ if (params->ssid) {
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
+ if (params->ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
+ goto fail;
+ if (params->auth_data) {
+ wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
+ params->auth_data_len);
+ if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
+ params->auth_data))
+ goto fail;
+ }
+ type = get_nl_auth_type(params->auth_alg);
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
+ if (params->local_state_change) {
+ wpa_printf(MSG_DEBUG, " * Local state change only");
+ if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
+ count, ret, strerror(-ret));
+ count++;
+ if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
+ params->bssid && !params->local_state_change) {
+ /*
+ * mac80211 does not currently accept new
+ * authentication if we are already authenticated. As a
+ * workaround, force deauthentication and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
+ "after forced deauthentication");
+ drv->ignore_deauth_event = 1;
+ wpa_driver_nl80211_deauthenticate(
+ bss, params->bssid,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ nlmsg_free(msg);
+ goto retry;
+ }
+
+ if (ret == -ENOENT && params->freq && !is_retry) {
+ /*
+ * cfg80211 has likely expired the BSS entry even
+ * though it was previously available in our internal
+ * BSS table. To recover quickly, start a single
+ * channel scan on the specified channel.
+ */
+ struct wpa_driver_scan_params scan;
+ int freqs[2];
+
+ os_memset(&scan, 0, sizeof(scan));
+ scan.num_ssids = 1;
+ if (params->ssid) {
+ scan.ssids[0].ssid = params->ssid;
+ scan.ssids[0].ssid_len = params->ssid_len;
+ }
+ freqs[0] = params->freq;
+ freqs[1] = 0;
+ scan.freqs = freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+ "channel scan to refresh cfg80211 BSS "
+ "entry");
+ ret = wpa_driver_nl80211_scan(bss, &scan);
+ if (ret == 0) {
+ nl80211_copy_auth_params(drv, params);
+ drv->scan_for_auth = 1;
+ }
+ } else if (is_retry) {
+ /*
+ * Need to indicate this with an event since the return
+ * value from the retry is not delivered to core code.
+ */
+ union wpa_event_data event;
+ wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+ "failed");
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+ ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+ &event);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication request send successfully");
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_driver_auth_params params;
+ struct i802_bss *bss = drv->first_bss;
+ int i;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+ os_memset(&params, 0, sizeof(params));
+ params.freq = drv->auth_freq;
+ params.auth_alg = drv->auth_alg;
+ params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+ params.local_state_change = drv->auth_local_state_change;
+ params.p2p = drv->auth_p2p;
+
+ if (!is_zero_ether_addr(drv->auth_bssid_))
+ params.bssid = drv->auth_bssid_;
+
+ if (drv->auth_ssid_len) {
+ params.ssid = drv->auth_ssid;
+ params.ssid_len = drv->auth_ssid_len;
+ }
+
+ params.ie = drv->auth_ie;
+ params.ie_len = drv->auth_ie_len;
+ params.auth_data = drv->auth_data;
+ params.auth_data_len = drv->auth_data_len;
+
+ for (i = 0; i < 4; i++) {
+ if (drv->auth_wep_key_len[i]) {
+ params.wep_key[i] = drv->auth_wep_key[i];
+ params.wep_key_len[i] = drv->auth_wep_key_len[i];
+ }
+ }
+
+ drv->retry_auth = 1;
+ return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+ size_t data_len, int noack,
+ unsigned int freq, int no_cck,
+ int offchanok,
+ unsigned int wait_time,
+ const u16 *csa_offs,
+ size_t csa_offs_len, int no_encrypt)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_mgmt *mgmt;
+ int encrypt = !no_encrypt;
+ u16 fc;
+ int use_cookie = 1;
+ int res;
+
+ mgmt = (struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
+ " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
+ MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
+ no_encrypt, fc, fc2str(fc), drv->nlmode);
+
+ if ((is_sta_interface(drv->nlmode) ||
+ drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
+ /*
+ * The use of last_mgmt_freq is a bit of a hack,
+ * but it works due to the single-threaded nature
+ * of wpa_supplicant.
+ */
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
+ drv->last_mgmt_freq);
+ freq = drv->last_mgmt_freq;
+ }
+ wait_time = 0;
+ use_cookie = 0;
+ no_cck = 1;
+ offchanok = 1;
+ goto send_frame_cmd;
+ }
+
+ if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
+ bss->freq);
+ freq = bss->freq;
+ }
+ if ((int) freq == bss->freq)
+ wait_time = 0;
+ goto send_frame_cmd;
+ }
+
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ /*
+ * Only one of the authentication frame types is encrypted.
+ * In order for static WEP encryption to work properly (i.e.,
+ * to not encrypt the frame), we need to tell mac80211 about
+ * the frames that must not be encrypted.
+ */
+ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
+ if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
+ encrypt = 0;
+ }
+
+ if (is_sta_interface(drv->nlmode) &&
+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ if (freq == 0 &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+ freq);
+ }
+
+ /* Allow off channel for PASN authentication */
+ if (data_len >= IEEE80211_HDRLEN + 2 &&
+ WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
+ !offchanok) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme: allow off channel for PASN");
+ offchanok = 1;
+ }
+ }
+
+#ifdef CONFIG_PASN
+ if (is_sta_interface(drv->nlmode) &&
+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DEAUTH) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme: allow Deauthentication frame for PASN");
+
+ use_cookie = 0;
+ offchanok = 1;
+ goto send_frame_cmd;
+ }
+#endif /* CONFIG_PASN */
+
+ if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
+ freq);
+ }
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
+ bss->freq);
+ freq = bss->freq;
+ }
+
+ if (drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
+ freq, bss->freq);
+ return nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ }
+
+ if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+ use_cookie = 0;
+send_frame_cmd:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (no_encrypt && !encrypt && !drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
+ if (nl80211_create_monitor_interface(drv) < 0)
+ return -1;
+ res = nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ nl80211_remove_monitor_interface(drv);
+ return res;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
+ res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
+ use_cookie, no_cck, noack, offchanok,
+ csa_offs, csa_offs_len);
+
+ return res;
+}
+
+
+static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
+{
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ if (!basic_rates)
+ return 0;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+ rates[rates_len++] = basic_rates[i] / 5;
+
+ return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+}
+
+
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+ int slot, int ht_opmode, int ap_isolate,
+ const int *basic_rates)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
+ (cts >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
+ (preamble >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
+ (slot >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
+ (ht_opmode >= 0 &&
+ nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
+ (ap_isolate >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
+ nl80211_put_basic_rates(msg, basic_rates)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int wpa_driver_nl80211_set_acl(void *priv,
+ struct hostapd_acl_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nl_msg *acl;
+ unsigned int i;
+ int ret;
+ size_t acl_nla_sz, acl_nlmsg_sz, nla_sz, nlmsg_sz;
+
+ if (!(drv->capa.max_acl_mac_addrs))
+ return -ENOTSUP;
+
+ if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+ return -ENOTSUP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+ params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+ acl_nla_sz = nla_total_size(ETH_ALEN) * params->num_mac_acl;
+ acl_nlmsg_sz = nlmsg_total_size(acl_nla_sz);
+ acl = nlmsg_alloc_size(acl_nlmsg_sz);
+ 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;
+ }
+ }
+
+ /*
+ * genetlink message header (Length of user header is 0) +
+ * u32 attr: NL80211_ATTR_IFINDEX +
+ * u32 attr: NL80211_ATTR_ACL_POLICY +
+ * nested acl attr
+ */
+ nla_sz = GENL_HDRLEN +
+ nla_total_size(4) * 2 +
+ nla_total_size(acl_nla_sz);
+ nlmsg_sz = nlmsg_total_size(nla_sz);
+ if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz),
+ drv->ifindex, 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) ||
+ nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
+ nlmsg_free(msg);
+ nlmsg_free(acl);
+ return -ENOMEM;
+ }
+ nlmsg_free(acl);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
+{
+ if (beacon_int > 0) {
+ wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
+ return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ beacon_int);
+ }
+
+ return 0;
+}
+
+
+static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
+{
+ if (dtim_period > 0) {
+ wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
+ return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_MESH
+static int nl80211_set_mesh_config(void *priv,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
+ if (!msg)
+ return -1;
+
+ ret = nl80211_put_mesh_config(msg, params);
+ if (ret < 0) {
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Mesh config set failed: %d (%s)",
+ ret, strerror(-ret));
+ return ret;
+ }
+ return 0;
+}
+#endif /* CONFIG_MESH */
+
+
+static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *bands, *band;
+ struct nl80211_txrate_vht vht_rate;
+ struct nl80211_txrate_he he_rate;
+
+ if (!params->freq ||
+ (params->beacon_rate == 0 &&
+ params->rate_type == BEACON_RATE_LEGACY))
+ return 0;
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ return -1;
+
+ switch (params->freq->mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
+ band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ if (is_6ghz_freq(params->freq->freq))
+ band = nla_nest_start(msg, NL80211_BAND_6GHZ);
+ else
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ band = nla_nest_start(msg, NL80211_BAND_60GHZ);
+ break;
+ default:
+ return 0;
+ }
+
+ if (!band)
+ return -1;
+
+ os_memset(&vht_rate, 0, sizeof(vht_rate));
+ os_memset(&he_rate, 0, sizeof(he_rate));
+
+ switch (params->rate_type) {
+ case BEACON_RATE_LEGACY:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (legacy)");
+ return -1;
+ }
+
+ if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
+ (u8) params->beacon_rate / 5) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_HT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HT)");
+ return -1;
+ }
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_VHT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (VHT)");
+ return -1;
+ }
+ vht_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_HE:
+ if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HE)");
+ return -1;
+ }
+ he_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate) ||
+ nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
+ params->beacon_rate);
+ break;
+ }
+
+ nla_nest_end(msg, band);
+ nla_nest_end(msg, bands);
+
+ return 0;
+}
+
+
+static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
+ int multicast_to_unicast)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
+ if (!msg ||
+ (multicast_to_unicast &&
+ nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
+ bss->ifname);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+
+ switch (ret) {
+ case 0:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: multicast to unicast %s on interface %s",
+ multicast_to_unicast ? "enabled" : "disabled",
+ bss->ifname);
+ break;
+ case -EOPNOTSUPP:
+ if (!multicast_to_unicast)
+ break;
+ wpa_printf(MSG_INFO,
+ "nl80211: multicast to unicast not supported on interface %s",
+ bss->ifname);
+ break;
+ default:
+ wpa_printf(MSG_ERROR,
+ "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
+ multicast_to_unicast ? "enabling" : "disabling",
+ ret, strerror(-ret), bss->ifname);
+ break;
+ }
+
+ return ret;
+}
+
+
+#ifdef CONFIG_SAE
+static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
+{
+ u8 sae_pwe;
+
+ wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
+ if (pwe == 0)
+ sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
+ else if (pwe == 1)
+ sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
+ else if (pwe == 2)
+ sae_pwe = NL80211_SAE_PWE_BOTH;
+ else if (pwe == 3)
+ return 0; /* special test mode */
+ else
+ return -1;
+ if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
+ return -1;
+
+ return 0;
+}
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->fils_discovery) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support FILS Discovery frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ params->fd_min_int) ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ params->fd_max_int) ||
+ (params->fd_frame_tmpl &&
+ nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
+ params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
+#ifdef CONFIG_IEEE80211AX
+static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
+ struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->unsol_bcast_probe_resp) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
+ params->unsol_bcast_probe_resp_interval);
+ attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
+ params->unsol_bcast_probe_resp_interval) ||
+ (params->unsol_bcast_probe_resp_tmpl &&
+ nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
+ params->unsol_bcast_probe_resp_tmpl_len,
+ params->unsol_bcast_probe_resp_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
+static int wpa_driver_nl80211_set_ap(void *priv,
+ struct wpa_driver_ap_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ u8 cmd = NL80211_CMD_NEW_BEACON;
+ int ret = -ENOBUFS;
+ int beacon_set;
+ int num_suites;
+ u32 suites[20], suite;
+ u32 ver;
+#ifdef CONFIG_MESH
+ struct wpa_driver_mesh_bss_params mesh_params;
+#endif /* CONFIG_MESH */
+
+ beacon_set = params->reenable ? 0 : bss->beacon_set;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
+ beacon_set);
+ if (beacon_set)
+ cmd = NL80211_CMD_SET_BEACON;
+ else if (!drv->device_ap_sme && !drv->use_monitor &&
+ !nl80211_get_wiphy_data_ap(bss))
+ return -ENOBUFS;
+
+ wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
+ params->head, params->head_len);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
+ params->tail, params->tail_len);
+ wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
+ wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
+ wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
+ wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
+ wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
+ params->head) ||
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
+ params->tail) ||
+ nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
+ params) ||
+ nl80211_put_dtim_period(msg, params->dtim_period) ||
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
+ if (params->proberesp && params->proberesp_len) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
+ params->proberesp, params->proberesp_len);
+ if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+ params->proberesp))
+ goto fail;
+ }
+ switch (params->hide_ssid) {
+ case NO_SSID_HIDING:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_NOT_IN_USE))
+ goto fail;
+ break;
+ case HIDDEN_SSID_ZERO_LEN:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_LEN))
+ goto fail;
+ break;
+ case HIDDEN_SSID_ZERO_CONTENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS))
+ goto fail;
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
+ if (params->privacy &&
+ nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ goto fail;
+ wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
+ if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
+ (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
+ /* Leave out the attribute */
+ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_SHARED_KEY))
+ goto fail;
+ } else {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_OPEN_SYSTEM))
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
+ ver = 0;
+ if (params->wpa_version & WPA_PROTO_WPA)
+ ver |= NL80211_WPA_VERSION_1;
+ if (params->wpa_version & WPA_PROTO_RSN)
+ ver |= NL80211_WPA_VERSION_2;
+ if (ver &&
+ nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+ params->key_mgmt_suites);
+ num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
+ suites, ARRAY_SIZE(suites));
+ if (num_suites > NL80211_MAX_NR_AKM_SUITES)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
+ num_suites);
+ else if (num_suites &&
+ nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+ suites))
+ goto fail;
+
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ (!params->pairwise_ciphers ||
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+ goto fail;
+
+ if (drv->device_ap_sme &&
+ (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+ params->pairwise_ciphers);
+ num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
+ suites, ARRAY_SIZE(suites));
+ if (num_suites &&
+ nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ num_suites * sizeof(u32), suites))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+ params->group_cipher);
+ suite = wpa_cipher_to_cipher_suite(params->group_cipher);
+ if (suite &&
+ nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
+ goto fail;
+
+ if (params->beacon_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
+ params->beacon_ies);
+ if (nla_put(msg, NL80211_ATTR_IE,
+ wpabuf_len(params->beacon_ies),
+ wpabuf_head(params->beacon_ies)))
+ goto fail;
+ }
+ if (params->proberesp_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
+ params->proberesp_ies);
+ if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ wpabuf_len(params->proberesp_ies),
+ wpabuf_head(params->proberesp_ies)))
+ goto fail;
+ }
+ if (params->assocresp_ies) {
+ wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
+ params->assocresp_ies);
+ if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ wpabuf_len(params->assocresp_ies),
+ wpabuf_head(params->assocresp_ies)))
+ goto fail;
+ }
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
+ wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
+ params->ap_max_inactivity);
+ if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+ params->ap_max_inactivity))
+ goto fail;
+ }
+
+#ifdef CONFIG_P2P
+ if (params->p2p_go_ctwindow > 0) {
+ if (drv->p2p_go_ctwindow_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
+ params->p2p_go_ctwindow);
+ if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
+ params->p2p_go_ctwindow))
+ goto fail;
+ } else {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ if (params->pbss) {
+ wpa_printf(MSG_DEBUG, "nl80211: PBSS");
+ if (nla_put_flag(msg, NL80211_ATTR_PBSS))
+ goto fail;
+ }
+
+ if (params->ftm_responder) {
+ struct nlattr *ftm;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
+ if (!ftm ||
+ nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
+ (params->lci &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
+ wpabuf_len(params->lci),
+ wpabuf_head(params->lci))) ||
+ (params->civic &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
+ wpabuf_len(params->civic),
+ wpabuf_head(params->civic))))
+ goto fail;
+ nla_nest_end(msg, ftm);
+ }
+
+#ifdef CONFIG_IEEE80211AX
+ if (params->he_spr_ctrl) {
+ struct nlattr *spr;
+
+ spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
+ params->he_spr_ctrl);
+
+ if (!spr ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
+ params->he_spr_ctrl) ||
+ ((params->he_spr_ctrl &
+ SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
+ params->he_spr_non_srg_obss_pd_max_offset)))
+ goto fail;
+
+ if ((params->he_spr_ctrl &
+ SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
+ (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
+ sizeof(params->he_spr_bss_color_bitmap),
+ params->he_spr_bss_color_bitmap) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
+ sizeof(params->he_spr_partial_bssid_bitmap),
+ params->he_spr_partial_bssid_bitmap)))
+ goto fail;
+
+ nla_nest_end(msg, spr);
+ }
+
+ if (params->freq && params->freq->he_enabled) {
+ struct nlattr *bss_color;
+
+ bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
+ if (!bss_color ||
+ (params->he_bss_color_disabled &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
+ (params->he_bss_color_partial &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
+ nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ params->he_bss_color))
+ goto fail;
+ nla_nest_end(msg, bss_color);
+ }
+
+ if (params->twt_responder) {
+ wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
+ params->twt_responder);
+ if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
+ goto fail;
+ }
+
+ if (params->unsol_bcast_probe_resp_interval &&
+ nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
+ goto fail;
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_SAE
+ if (((params->key_mgmt_suites & WPA_KEY_MGMT_SAE) ||
+ (params->key_mgmt_suites & WPA_KEY_MGMT_FT_SAE)) &&
+ nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
+ goto fail;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
+ goto fail;
+#endif /* CONFIG_FILS */
+
+ ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
+ ret, strerror(-ret));
+ } else {
+ bss->beacon_set = 1;
+ nl80211_set_bss(bss, params->cts_protect, params->preamble,
+ params->short_slot_time, params->ht_opmode,
+ params->isolate, params->basic_rates);
+ nl80211_set_multicast_to_unicast(bss,
+ params->multicast_to_unicast);
+ if (beacon_set && params->freq &&
+ params->freq->bandwidth != bss->bandwidth) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Update BSS %s bandwidth: %d -> %d",
+ bss->ifname, bss->bandwidth,
+ params->freq->bandwidth);
+ ret = nl80211_set_channel(bss, params->freq, 1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frequency set failed: %d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frequency set succeeded for ht2040 coex");
+ bss->bandwidth = params->freq->bandwidth;
+ }
+ } else if (!beacon_set && params->freq) {
+ /*
+ * cfg80211 updates the driver on frequence change in AP
+ * mode only at the point when beaconing is started, so
+ * set the initial value here.
+ */
+ bss->bandwidth = params->freq->bandwidth;
+ }
+ }
+
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
+ os_memset(&mesh_params, 0, sizeof(mesh_params));
+ mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ mesh_params.ht_opmode = params->ht_opmode;
+ ret = nl80211_set_mesh_config(priv, &mesh_params);
+ if (ret < 0)
+ return ret;
+ }
+#endif /* CONFIG_MESH */
+
+ return ret;
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_put_freq_params(struct nl_msg *msg,
+ const struct hostapd_freq_params *freq)
+{
+ enum hostapd_hw_mode hw_mode;
+ int is_24ghz;
+ u8 channel;
+
+ wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+ return -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
+ wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
+ wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
+ if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
+ enum nl80211_chan_width cw;
+
+ wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
+ switch (freq->bandwidth) {
+ case 20:
+ cw = NL80211_CHAN_WIDTH_20;
+ break;
+ case 40:
+ cw = NL80211_CHAN_WIDTH_40;
+ break;
+ case 80:
+ if (freq->center_freq2)
+ cw = NL80211_CHAN_WIDTH_80P80;
+ else
+ cw = NL80211_CHAN_WIDTH_80;
+ break;
+ case 160:
+ cw = NL80211_CHAN_WIDTH_160;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
+ wpa_printf(MSG_DEBUG, " * center_freq1=%d",
+ freq->center_freq1);
+ wpa_printf(MSG_DEBUG, " * center_freq2=%d",
+ freq->center_freq2);
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
+ freq->center_freq1) ||
+ (freq->center_freq2 &&
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
+ freq->center_freq2)))
+ return -ENOBUFS;
+ } else if (freq->ht_enabled) {
+ enum nl80211_channel_type ct;
+
+ wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
+ freq->sec_channel_offset);
+ switch (freq->sec_channel_offset) {
+ case -1:
+ ct = NL80211_CHAN_HT40MINUS;
+ break;
+ case 1:
+ ct = NL80211_CHAN_HT40PLUS;
+ break;
+ default:
+ ct = NL80211_CHAN_HT20;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
+ return -ENOBUFS;
+ } else if (freq->edmg.channels && freq->edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ freq->edmg.channels, freq->edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ freq->edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ freq->edmg.bw_config))
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, " * channel_type=%d",
+ NL80211_CHAN_NO_HT);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_NO_HT))
+ return -ENOBUFS;
+ }
+ return 0;
+}
+
+
+static int nl80211_set_channel(struct i802_bss *bss,
+ struct hostapd_freq_params *freq, int set_chan)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
+ freq->bandwidth, freq->center_freq1, freq->center_freq2);
+
+ msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ NL80211_CMD_SET_WIPHY);
+ if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret == 0) {
+ bss->freq = freq->freq;
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
+ "%d (%s)", freq->freq, ret, strerror(-ret));
+ return -1;
+}
+
+
+static u32 sta_flags_nl80211(int flags)
+{
+ u32 f = 0;
+
+ if (flags & WPA_STA_AUTHORIZED)
+ f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (flags & WPA_STA_WMM)
+ f |= BIT(NL80211_STA_FLAG_WME);
+ if (flags & WPA_STA_SHORT_PREAMBLE)
+ f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+ if (flags & WPA_STA_MFP)
+ f |= BIT(NL80211_STA_FLAG_MFP);
+ if (flags & WPA_STA_TDLS_PEER)
+ f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (flags & WPA_STA_AUTHENTICATED)
+ f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (flags & WPA_STA_ASSOCIATED)
+ f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+
+ return f;
+}
+
+
+#ifdef CONFIG_MESH
+static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
+{
+ switch (state) {
+ case PLINK_IDLE:
+ return NL80211_PLINK_LISTEN;
+ case PLINK_OPN_SNT:
+ return NL80211_PLINK_OPN_SNT;
+ case PLINK_OPN_RCVD:
+ return NL80211_PLINK_OPN_RCVD;
+ case PLINK_CNF_RCVD:
+ return NL80211_PLINK_CNF_RCVD;
+ case PLINK_ESTAB:
+ return NL80211_PLINK_ESTAB;
+ case PLINK_HOLDING:
+ return NL80211_PLINK_HOLDING;
+ case PLINK_BLOCKED:
+ return NL80211_PLINK_BLOCKED;
+ default:
+ wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
+ state);
+ }
+ return -1;
+}
+#endif /* CONFIG_MESH */
+
+
+static int wpa_driver_nl80211_sta_add(void *priv,
+ struct hostapd_sta_add_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nl80211_sta_flag_update upd;
+ int ret = -ENOBUFS;
+
+ if ((params->flags & WPA_STA_TDLS_PEER) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
+ params->set ? "Set" : "Add", MAC2STR(params->addr));
+ msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
+ NL80211_CMD_NEW_STATION);
+ if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+ goto fail;
+
+ /*
+ * Set the below properties only in one of the following cases:
+ * 1. New station is added, already associated.
+ * 2. Set WPA_STA_TDLS_PEER station.
+ * 3. Set an already added unassociated station, if driver supports
+ * full AP client state. (Set these properties after station became
+ * associated will be rejected by the driver).
+ */
+ if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
+ (params->flags & WPA_STA_ASSOCIATED))) {
+ wpa_hexdump(MSG_DEBUG, " * supported rates",
+ params->supp_rates, params->supp_rates_len);
+ wpa_printf(MSG_DEBUG, " * capability=0x%x",
+ params->capability);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
+ params->supp_rates_len, params->supp_rates) ||
+ nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
+ params->capability))
+ goto fail;
+
+ if (params->ht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
+ (u8 *) params->ht_capabilities,
+ sizeof(*params->ht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
+ sizeof(*params->ht_capabilities),
+ params->ht_capabilities))
+ goto fail;
+ }
+
+ if (params->vht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
+ (u8 *) params->vht_capabilities,
+ sizeof(*params->vht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
+ sizeof(*params->vht_capabilities),
+ params->vht_capabilities))
+ goto fail;
+ }
+
+ if (params->he_capab) {
+ wpa_hexdump(MSG_DEBUG, " * he_capab",
+ params->he_capab, params->he_capab_len);
+ if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
+ params->he_capab_len, params->he_capab))
+ goto fail;
+ }
+
+ if (params->he_6ghz_capab) {
+ wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
+ params->he_6ghz_capab,
+ sizeof(*params->he_6ghz_capab));
+ if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
+ sizeof(*params->he_6ghz_capab),
+ params->he_6ghz_capab))
+ goto fail;
+ }
+
+ if (params->ext_capab) {
+ wpa_hexdump(MSG_DEBUG, " * ext_capab",
+ params->ext_capab, params->ext_capab_len);
+ if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+ params->ext_capab_len, params->ext_capab))
+ goto fail;
+ }
+
+ if (is_ap_interface(drv->nlmode) &&
+ nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
+ params->support_p2p_ps ?
+ NL80211_P2P_PS_SUPPORTED :
+ NL80211_P2P_PS_UNSUPPORTED))
+ goto fail;
+ }
+ if (!params->set) {
+ if (params->aid) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
+ goto fail;
+ } else {
+ /*
+ * cfg80211 validates that AID is non-zero, so we have
+ * to make this a non-zero value for the TDLS case where
+ * a dummy STA entry is used for now and for a station
+ * that is still not associated.
+ */
+ wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
+ (params->flags & WPA_STA_TDLS_PEER) ?
+ "TDLS" : "UNASSOC_STA");
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval))
+ goto fail;
+ } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+ wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
+ if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
+ goto fail;
+ } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
+ (params->flags & WPA_STA_ASSOCIATED)) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
+ nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval))
+ goto fail;
+ }
+
+ if (params->vht_opmode_enabled) {
+ wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
+ if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
+ params->vht_opmode))
+ goto fail;
+ }
+
+ if (params->supp_channels) {
+ wpa_hexdump(MSG_DEBUG, " * supported channels",
+ params->supp_channels, params->supp_channels_len);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+ params->supp_channels_len, params->supp_channels))
+ goto fail;
+ }
+
+ if (params->supp_oper_classes) {
+ wpa_hexdump(MSG_DEBUG, " * supported operating classes",
+ params->supp_oper_classes,
+ params->supp_oper_classes_len);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+ params->supp_oper_classes_len,
+ params->supp_oper_classes))
+ goto fail;
+ }
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.set = sta_flags_nl80211(params->flags);
+ upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
+
+ /*
+ * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
+ * flags, as nl80211 driver moves a new station, by default, into
+ * associated state.
+ *
+ * On the other hand, if the driver supports that feature and the
+ * station is added in unauthenticated state, set the
+ * authenticated/associated bits in the mask to prevent moving this
+ * station to associated state before it is actually associated.
+ *
+ * This is irrelevant for mesh mode where the station is added to the
+ * driver as authenticated already, and ASSOCIATED isn't part of the
+ * nl80211 API.
+ */
+ if (!is_mesh_interface(drv->nlmode)) {
+ if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
+ upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED));
+ } else if (!params->set &&
+ !(params->flags & WPA_STA_TDLS_PEER)) {
+ if (!(params->flags & WPA_STA_AUTHENTICATED))
+ upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (!(params->flags & WPA_STA_ASSOCIATED))
+ upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ }
+#ifdef CONFIG_MESH
+ } else {
+ if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
+ ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
+ params->peer_aid);
+ if (ret)
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
+ }
+
+ wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
+ upd.set, upd.mask);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
+
+#ifdef CONFIG_MESH
+ if (params->plink_state &&
+ nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
+ sta_plink_state_nl80211(params->plink_state)))
+ goto fail;
+#endif /* CONFIG_MESH */
+
+ if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
+ (params->flags & WPA_STA_WMM)) {
+ struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
+ wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
+ if (!wme ||
+ nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
+ params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
+ nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
+ WMM_QOSINFO_STA_SP_MASK))
+ goto fail;
+ nla_nest_end(msg, wme);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+ "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+ strerror(-ret));
+ if (ret == -EEXIST)
+ ret = 0;
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_addr;
+ int err;
+
+ rn = rtnl_neigh_alloc();
+ if (!rn)
+ return;
+
+ rtnl_neigh_set_family(rn, AF_BRIDGE);
+ rtnl_neigh_set_ifindex(rn, bss->ifindex);
+ nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
+ if (!nl_addr) {
+ rtnl_neigh_put(rn);
+ return;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_addr);
+
+ err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
+ MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
+ bss->ifindex, nl_geterror(err));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
+ MACSTR, MAC2STR(addr));
+ }
+
+ nl_addr_put(nl_addr);
+ rtnl_neigh_put(rn);
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
+ int deauth, u16 reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ (deauth == 0 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DISASSOC)) ||
+ (deauth == 1 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DEAUTH)) ||
+ (reason_code &&
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
+ " --> %d (%s)",
+ bss->ifname, MAC2STR(addr), ret, strerror(-ret));
+
+ if (drv->rtnl_sk)
+ rtnl_neigh_delete_fdb_entry(bss, addr);
+
+ if (ret == -ENOENT)
+ return 0;
+ return ret;
+}
+
+
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv2;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
+
+ /* stop listening for EAPOL on this interface */
+ dl_list_for_each(drv2, &drv->global->interfaces,
+ struct wpa_driver_nl80211_data, list)
+ {
+ del_ifidx(drv2, ifidx, IFIDX_ANY);
+ /* Remove all bridges learned for this iface */
+ del_ifidx(drv2, IFIDX_ANY, ifidx);
+ }
+
+ msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
+ return;
+ wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
+}
+
+
+const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+ switch (mode) {
+ case NL80211_IFTYPE_ADHOC:
+ return "ADHOC";
+ case NL80211_IFTYPE_STATION:
+ return "STATION";
+ case NL80211_IFTYPE_AP:
+ return "AP";
+ case NL80211_IFTYPE_AP_VLAN:
+ return "AP_VLAN";
+ case NL80211_IFTYPE_WDS:
+ return "WDS";
+ case NL80211_IFTYPE_MONITOR:
+ return "MONITOR";
+ case NL80211_IFTYPE_MESH_POINT:
+ return "MESH_POINT";
+ case NL80211_IFTYPE_P2P_CLIENT:
+ return "P2P_CLIENT";
+ case NL80211_IFTYPE_P2P_GO:
+ return "P2P_GO";
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return "P2P_DEVICE";
+ case NL80211_IFTYPE_OCB:
+ return "OCB";
+ case NL80211_IFTYPE_NAN:
+ return "NAN";
+ default:
+ return "unknown";
+ }
+}
+
+
+static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg)
+{
+ struct nl_msg *msg;
+ int ifidx;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+ iftype, nl80211_iftype_str(iftype));
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
+ if (!msg ||
+ nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
+ nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
+ goto fail;
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ struct nlattr *flags;
+
+ flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
+ if (!flags ||
+ nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
+ goto fail;
+
+ nla_nest_end(msg, flags);
+ } else if (wds) {
+ if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
+ goto fail;
+ }
+
+ /*
+ * Tell cfg80211 that the interface belongs to the socket that created
+ * it, and the interface should be deleted when the socket is closed.
+ */
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ goto fail;
+
+ if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
+ ifname, ret, strerror(-ret));
+ return ret;
+ }
+
+ if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+
+ ifidx = if_nametoindex(ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
+ ifname, ifidx);
+
+ if (ifidx <= 0)
+ return -1;
+
+ /*
+ * Some virtual interfaces need to process EAPOL packets and events on
+ * the parent interface. This is used mainly with hostapd.
+ */
+ if (drv->hostapd ||
+ iftype == NL80211_IFTYPE_AP_VLAN ||
+ iftype == NL80211_IFTYPE_WDS ||
+ iftype == NL80211_IFTYPE_MONITOR) {
+ /* start listening for EAPOL on this interface */
+ add_ifidx(drv, ifidx, IFIDX_ANY);
+ }
+
+ if (addr && iftype != NL80211_IFTYPE_MONITOR &&
+ linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+
+ return ifidx;
+}
+
+
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing)
+{
+ int ret;
+
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+ arg);
+
+ /* if error occurred and interface exists already */
+ if (ret == -ENFILE && if_nametoindex(ifname)) {
+ if (use_existing) {
+ wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+ ifname);
+ if (addr && iftype != NL80211_IFTYPE_MONITOR &&
+ linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+ addr) < 0 &&
+ (linux_set_iface_flags(drv->global->ioctl_sock,
+ ifname, 0) < 0 ||
+ linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+ addr) < 0 ||
+ linux_set_iface_flags(drv->global->ioctl_sock,
+ ifname, 1) < 0))
+ return -1;
+ return -ENFILE;
+ }
+ wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
+
+ /* Try to remove the interface that was already there. */
+ nl80211_remove_iface(drv, if_nametoindex(ifname));
+
+ /* Try to create the interface again */
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
+ wds, handler, arg);
+ }
+
+ if (ret >= 0 && is_p2p_net_interface(iftype)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s created for P2P - disable 11b rates",
+ ifname);
+ nl80211_disable_11b_rates(drv, ret, 1);
+ }
+
+ return ret;
+}
+
+
+static int nl80211_setup_ap(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
+
+ /*
+ * Disable Probe Request reporting unless we need it in this way for
+ * devices that include the AP SME, in the other case (unless using
+ * monitor iface) we'll get it through the nl_mgmt socket instead.
+ */
+ if (!drv->device_ap_sme)
+ wpa_driver_nl80211_probe_req_report(bss, 0);
+
+ if (!drv->device_ap_sme && !drv->use_monitor)
+ if (nl80211_mgmt_subscribe_ap(bss))
+ return -1;
+
+ if (drv->device_ap_sme && !drv->use_monitor)
+ if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
+
+ if (!drv->device_ap_sme && drv->use_monitor &&
+ nl80211_create_monitor_interface(drv) &&
+ !drv->device_ap_sme)
+ return -1;
+
+ if (drv->device_ap_sme &&
+ wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+ "Probe Request frame reporting in AP mode");
+ /* Try to survive without this */
+ }
+
+ return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
+ bss->ifname, drv->device_ap_sme, drv->use_monitor);
+ if (drv->device_ap_sme) {
+ wpa_driver_nl80211_probe_req_report(bss, 0);
+ if (!drv->use_monitor)
+ nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+ } else if (drv->use_monitor)
+ nl80211_remove_monitor_interface(drv);
+ else
+ nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+ nl80211_put_wiphy_data_ap(bss);
+ bss->beacon_set = 0;
+}
+
+
+static int nl80211_tx_control_port(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ struct nl80211_ack_ext_arg ext_arg;
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ u64 cookie = 0;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Send over control port dest=" MACSTR
+ " proto=0x%04x len=%u no_encrypt=%d",
+ MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+ (no_encrypt &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
+ ext_arg.ext_data = &cookie;
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
+ ack_handler_cookie, &ext_arg);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port cookie=0x%llx",
+ (long long unsigned int) cookie);
+ drv->eapol_tx_cookie = cookie;
+ }
+
+ return ret;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+ const u8 *addr, const u8 *data,
+ size_t data_len)
+{
+ struct sockaddr_ll ll;
+ int ret;
+
+ if (bss->drv->eapol_tx_sock < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+ return -1;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = bss->ifindex;
+ ll.sll_protocol = htons(ETH_P_PAE);
+ ll.sll_halen = ETH_ALEN;
+ os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+ ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+ (struct sockaddr *) &ll, sizeof(ll));
+ if (ret < 0)
+ wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+ strerror(errno));
+
+ return ret;
+}
+
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+static int wpa_driver_nl80211_hapd_send_eapol(
+ void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+ int qos = flags & WPA_STA_WMM;
+
+ /* For now, disable EAPOL TX over control port in AP mode by default
+ * since it does not provide TX status notifications. */
+ if (drv->control_port_ap &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
+ return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
+ if (drv->device_ap_sme || !drv->use_monitor)
+ return nl80211_send_eapol_data(bss, addr, data, data_len);
+
+ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+ data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ if (qos) {
+ hdr->frame_control |=
+ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
+ }
+
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+ pos = (u8 *) (hdr + 1);
+
+ if (qos) {
+ /* Set highest priority in QoS header */
+ pos[0] = 7;
+ pos[1] = 0;
+ pos += 2;
+ }
+
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ WPA_PUT_BE16(pos, ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "hapd_send_eapol - packet len: %lu - failed",
+ (unsigned long) len);
+ }
+ os_free(hdr);
+
+ return res;
+}
+
+
+static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
+ unsigned int total_flags,
+ unsigned int flags_or,
+ unsigned int flags_and)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ struct nlattr *flags;
+ struct nl80211_sta_flag_update upd;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
+ " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
+ bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
+ !!(total_flags & WPA_STA_AUTHORIZED));
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
+
+ /*
+ * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
+ * can be removed eventually.
+ */
+ flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+ if (!flags ||
+ ((total_flags & WPA_STA_AUTHORIZED) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
+ ((total_flags & WPA_STA_WMM) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
+ ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
+ ((total_flags & WPA_STA_MFP) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
+ ((total_flags & WPA_STA_TDLS_PEER) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
+ goto fail;
+
+ nla_nest_end(msg, flags);
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
+ upd.set = sta_flags_nl80211(flags_or);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
+
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+fail:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
+ unsigned int weight)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
+ " weight=%u", bss->ifname, MAC2STR(addr), weight);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
+ goto fail;
+
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+fail:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ enum nl80211_iftype nlmode, old_mode;
+
+ if (params->p2p) {
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
+ "group (GO)");
+ nlmode = NL80211_IFTYPE_P2P_GO;
+ } else
+ nlmode = NL80211_IFTYPE_AP;
+
+ old_mode = drv->nlmode;
+ if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+ }
+
+ if (params->freq.freq &&
+ nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
+ if (old_mode != nlmode)
+ wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
+ ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Leave IBSS request sent successfully");
+ }
+
+ if (reset_mode &&
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ NL80211_IFTYPE_STATION)) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+ "station mode");
+ }
+
+ return ret;
+}
+
+
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+ struct wpa_driver_associate_params *params)
+{
+ if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+ return -1;
+
+ if (params->htcaps && params->htcaps_mask) {
+ int sz = sizeof(struct ieee80211_ht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
+ params->htcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+ params->htcaps) ||
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+ params->htcaps_mask))
+ return -1;
+ }
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+ return -1;
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
+ params->vhtcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+ params->vhtcaps) ||
+ nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask))
+ return -1;
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+#ifdef CONFIG_HE_OVERRIDES
+ if (params->disable_he) {
+ wpa_printf(MSG_DEBUG, " * HE disabled");
+ if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
+ return -1;
+ }
+#endif /* CONFIG_HE_OVERRIDES */
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+ int count = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
+
+ if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+ "IBSS mode");
+ return -1;
+ }
+
+retry:
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
+ params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+
+ if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
+ nl80211_put_beacon_int(msg, params->beacon_int))
+ goto fail;
+
+ ret = nl80211_set_conn_keys(params, msg);
+ if (ret)
+ goto fail;
+
+ if (params->bssid && params->fixed_bssid) {
+ wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
+ MAC2STR(params->bssid));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
+ }
+
+ if (params->fixed_freq) {
+ wpa_printf(MSG_DEBUG, " * fixed_freq");
+ if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
+ goto fail;
+ }
+
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
+ wpa_printf(MSG_DEBUG, " * control port");
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ goto fail;
+ }
+
+ if (params->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG,
+ " * Extra IEs for Beacon/Probe Response frames",
+ params->wpa_ie, params->wpa_ie_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie))
+ goto fail;
+ }
+
+ ret = nl80211_ht_vht_overrides(msg, params);
+ if (ret < 0)
+ goto fail;
+
+ ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ count++;
+ if (ret == -EALREADY && count == 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
+ "forced leave");
+ nl80211_leave_ibss(drv, 0);
+ nlmsg_free(msg);
+ goto retry;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Join IBSS request sent successfully");
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
+{
+ if (params->fils_erp_username_len) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
+ params->fils_erp_username,
+ params->fils_erp_username_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
+ params->fils_erp_username_len,
+ params->fils_erp_username))
+ return -1;
+ }
+
+ if (params->fils_erp_realm_len) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
+ params->fils_erp_realm,
+ params->fils_erp_realm_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
+ params->fils_erp_realm_len, params->fils_erp_realm))
+ return -1;
+ }
+
+ if (params->fils_erp_rrk_len) {
+ wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
+ params->fils_erp_next_seq_num);
+ if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ params->fils_erp_next_seq_num))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
+ (unsigned long) params->fils_erp_rrk_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
+ params->fils_erp_rrk_len, params->fils_erp_rrk))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
+{
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ return -1;
+
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ return -1;
+ }
+
+ if (params->bssid_hint) {
+ wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
+ MAC2STR(params->bssid_hint));
+ if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
+ params->bssid_hint))
+ return -1;
+ }
+
+ if (params->freq.freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ params->freq.freq))
+ return -1;
+ drv->assoc_freq = params->freq.freq;
+ } else
+ drv->assoc_freq = 0;
+
+ if (params->freq_hint) {
+ wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
+ params->freq_hint))
+ return -1;
+ }
+
+ if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ params->freq.edmg.channels,
+ params->freq.edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ params->freq.edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ params->freq.edmg.bw_config))
+ return -1;
+ }
+
+ if (params->bg_scan_period >= 0) {
+ wpa_printf(MSG_DEBUG, " * bg scan period=%d",
+ params->bg_scan_period);
+ if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+ params->bg_scan_period))
+ return -1;
+ }
+
+ if (params->ssid) {
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ return -1;
+ if (params->ssid_len > sizeof(drv->ssid))
+ return -1;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ }
+
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
+ if (params->wpa_ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
+ return -1;
+
+ if (params->wpa_proto) {
+ enum nl80211_wpa_versions ver = 0;
+
+ if (params->wpa_proto & WPA_PROTO_WPA)
+ ver |= NL80211_WPA_VERSION_1;
+ if (params->wpa_proto & WPA_PROTO_RSN)
+ ver |= NL80211_WPA_VERSION_2;
+
+ wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
+ if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ return -1;
+ }
+
+ if (params->pairwise_suite != WPA_CIPHER_NONE) {
+ u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
+ wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ cipher))
+ return -1;
+ }
+
+ if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
+ !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
+ /*
+ * This is likely to work even though many drivers do not
+ * advertise support for operations without GTK.
+ */
+ wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
+ } else if (params->group_suite != WPA_CIPHER_NONE) {
+ u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
+ wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
+ return -1;
+ }
+
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
+ int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+
+ switch (params->key_mgmt_suite) {
+ case WPA_KEY_MGMT_CCKM:
+ mgmt = RSN_AUTH_KEY_MGMT_CCKM;
+ break;
+ case WPA_KEY_MGMT_IEEE8021X:
+ mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
+ break;
+ case WPA_KEY_MGMT_FT_PSK:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
+ break;
+ case WPA_KEY_MGMT_IEEE8021X_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+ break;
+ case WPA_KEY_MGMT_PSK_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_OSEN:
+ mgmt = RSN_AUTH_KEY_MGMT_OSEN;
+ break;
+ case WPA_KEY_MGMT_SAE:
+ mgmt = RSN_AUTH_KEY_MGMT_SAE;
+ break;
+ case WPA_KEY_MGMT_FT_SAE:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
+ break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+ break;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ break;
+ case WPA_KEY_MGMT_FILS_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ break;
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case WPA_KEY_MGMT_OWE:
+ mgmt = RSN_AUTH_KEY_MGMT_OWE;
+ break;
+ case WPA_KEY_MGMT_DPP:
+ mgmt = RSN_AUTH_KEY_MGMT_DPP;
+ break;
+ case WPA_KEY_MGMT_PSK:
+ default:
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
+ if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+ return -1;
+ }
+
+ if (params->req_handshake_offload &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
+ wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
+ if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
+ return -1;
+ }
+
+ /* Add PSK in case of 4-way handshake offload */
+ if (params->psk &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+ wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
+ if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
+ return -1;
+ }
+
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ return -1;
+
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ (params->pairwise_suite == WPA_CIPHER_NONE ||
+ params->pairwise_suite == WPA_CIPHER_WEP104 ||
+ params->pairwise_suite == WPA_CIPHER_WEP40) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+ return -1;
+
+ if (params->rrm_used) {
+ u32 drv_rrm_flags = drv->capa.rrm_flags;
+ if ((!((drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+ (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+ !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
+ nla_put_flag(msg, NL80211_ATTR_USE_RRM))
+ return -1;
+ }
+
+ if (nl80211_ht_vht_overrides(msg, params) < 0)
+ return -1;
+
+ if (params->p2p)
+ wpa_printf(MSG_DEBUG, " * P2P group");
+
+ if (params->pbss) {
+ wpa_printf(MSG_DEBUG, " * PBSS");
+ if (nla_put_flag(msg, NL80211_ATTR_PBSS))
+ return -1;
+ }
+
+ drv->connect_reassoc = 0;
+ if (params->prev_bssid) {
+ wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
+ MAC2STR(params->prev_bssid));
+ if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid))
+ return -1;
+ drv->connect_reassoc = 1;
+ }
+
+ if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
+ nl80211_put_fils_connect_params(drv, params, msg) != 0)
+ return -1;
+
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
+ (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ return -1;
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_try_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ int ret;
+ int algs;
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (params->req_key_mgmt_offload && params->psk &&
+ (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
+ ret = issue_key_mgmt_set_key(drv, params->psk, 32);
+ if (ret)
+ return ret;
+ }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
+ if (!msg)
+ return -1;
+
+ ret = nl80211_connect_common(drv, params, msg);
+ if (ret)
+ goto fail;
+
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ goto fail;
+
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
+ goto fail;
+
+#ifdef CONFIG_SAE
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
+ nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
+ goto fail;
+#endif /* CONFIG_SAE */
+
+ algs = 0;
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+ algs++;
+ if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+ algs++;
+ if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+ algs++;
+ if (params->auth_alg & WPA_AUTH_ALG_FILS)
+ algs++;
+ if (params->auth_alg & WPA_AUTH_ALG_FT)
+ algs++;
+ if (algs > 1) {
+ wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
+ "selection");
+ goto skip_auth_type;
+ }
+
+ type = get_nl_auth_type(params->auth_alg);
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
+
+skip_auth_type:
+ ret = nl80211_set_conn_keys(params, msg);
+ if (ret)
+ goto fail;
+
+ ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ } else {
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ drv->roam_indication_done = false;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect request send successfully");
+ }
+
+fail:
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return ret;
+
+}
+
+
+static int wpa_driver_nl80211_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct i802_bss *bss)
+{
+ int ret;
+
+ /* Store the connection attempted bssid for future use */
+ if (params->bssid)
+ os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+ else
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
+
+ ret = wpa_driver_nl80211_try_connect(drv, params, bss);
+ if (ret == -EALREADY) {
+ /*
+ * cfg80211 does not currently accept new connections if
+ * we are already connected. As a workaround, force
+ * disconnection and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+ "disconnecting before reassociation "
+ "attempt");
+ if (wpa_driver_nl80211_disconnect(
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID, bss))
+ return -1;
+ ret = wpa_driver_nl80211_try_connect(drv, params, bss);
+ }
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+
+ nl80211_unmask_11b_rates(bss);
+
+ if (params->mode == IEEE80211_MODE_AP)
+ return wpa_driver_nl80211_ap(drv, params);
+
+ if (params->mode == IEEE80211_MODE_IBSS)
+ return wpa_driver_nl80211_ibss(drv, params);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ enum nl80211_iftype nlmode = params->p2p ?
+ NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+ if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+ return -1;
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
+ bss->use_nl_connect = 1;
+ else
+ bss->use_nl_connect = 0;
+
+ return wpa_driver_nl80211_connect(drv, params, bss);
+ }
+
+ nl80211_mark_disconnected(drv);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
+ drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
+ if (!msg)
+ return -1;
+
+ ret = nl80211_connect_common(drv, params, msg);
+ if (ret)
+ goto fail;
+
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ goto fail;
+
+ if (params->fils_kek) {
+ wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
+ (unsigned int) params->fils_kek_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
+ params->fils_kek))
+ goto fail;
+ }
+ if (params->fils_nonces) {
+ wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
+ params->fils_nonces,
+ params->fils_nonces_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
+ params->fils_nonces_len, params->fils_nonces))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
+ msg = NULL;
+ if (ret) {
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed (assoc): ret=%d (%s)",
+ ret, strerror(-ret));
+ nl80211_dump_scan(drv);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Association request send successfully");
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
+ int ifindex, enum nl80211_iftype mode)
+{
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
+ ifindex, mode, nl80211_iftype_str(mode));
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (!ret)
+ return 0;
+fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
+ " %d (%s)", ifindex, mode, ret, strerror(-ret));
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_mode_impl(
+ struct i802_bss *bss,
+ enum nl80211_iftype nlmode,
+ struct hostapd_freq_params *desired_freq_params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ int i;
+ int was_ap = is_ap_interface(drv->nlmode);
+ int res;
+ int mode_switch_res;
+
+ if (TEST_FAIL())
+ return -1;
+
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
+ mode_switch_res = 0;
+
+ if (mode_switch_res == 0) {
+ drv->nlmode = nlmode;
+ ret = 0;
+ goto done;
+ }
+
+ if (mode_switch_res == -ENODEV)
+ return -1;
+
+ if (nlmode == drv->nlmode) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
+ "requested mode - ignore error");
+ ret = 0;
+ goto done; /* Already in the requested mode */
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so
+ * take the device down, try to set the mode again, and bring the
+ * device back up.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
+ "interface down");
+ for (i = 0; i < 10; i++) {
+ res = i802_set_iface_flags(bss, 0);
+ if (res == -EACCES || res == -ENODEV)
+ break;
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
+ "interface down");
+ os_sleep(0, 100000);
+ continue;
+ }
+
+ /*
+ * Setting the mode will fail for some drivers if the phy is
+ * on a frequency that the mode is disallowed in.
+ */
+ if (desired_freq_params) {
+ res = nl80211_set_channel(bss, desired_freq_params, 0);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set frequency on interface");
+ }
+ }
+
+ if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
+ bss->brname[0] &&
+ (bss->added_if_into_bridge || bss->already_in_bridge)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
+ bss->ifname, bss->brname);
+ if (linux_br_del_if(drv->global->ioctl_sock,
+ bss->brname, bss->ifname) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to remove interface %s from bridge %s: %s",
+ bss->ifname, bss->brname,
+ strerror(errno));
+ }
+
+ /* Try to set the mode again while the interface is down */
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res == -EBUSY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Delaying mode set while interface going down");
+ os_sleep(0, 100000);
+ continue;
+ }
+ ret = mode_switch_res;
+ break;
+ }
+
+ if (!ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
+ "interface is down");
+ drv->nlmode = nlmode;
+ drv->ignore_if_down_event = 1;
+ }
+
+ /* Bring the interface back up */
+ res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set interface up after switching mode");
+ ret = -1;
+ }
+
+done:
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+ "from %d failed", nlmode, drv->nlmode);
+ return ret;
+ }
+
+ if (is_p2p_net_interface(nlmode)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode change to P2P - disable 11b rates",
+ bss->ifname);
+ nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+ } else if (drv->disabled_11b_rates) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
+ bss->ifname);
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+ }
+
+ if (is_ap_interface(nlmode)) {
+ nl80211_mgmt_unsubscribe(bss, "start AP");
+ /* Setup additional AP mode functionality if needed */
+ if (nl80211_setup_ap(bss))
+ return -1;
+ } else if (was_ap) {
+ /* Remove additional AP mode functionality */
+ nl80211_teardown_ap(bss);
+ } else {
+ nl80211_mgmt_unsubscribe(bss, "mode change");
+ }
+
+ if (is_mesh_interface(nlmode) &&
+ nl80211_mgmt_subscribe_mesh(bss))
+ return -1;
+
+ if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+ !is_mesh_interface(nlmode) &&
+ nl80211_mgmt_subscribe_non_ap(bss) < 0)
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+ "frame processing - ignore for now");
+
+ return 0;
+}
+
+
+void nl80211_restore_ap_mode(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int was_ap = is_ap_interface(drv->nlmode);
+
+ wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
+ if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
+ bss->brname[0] &&
+ (bss->added_if_into_bridge || bss->already_in_bridge)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add AP interface %s back into the bridge %s",
+ bss->ifname, bss->brname);
+ if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0) {
+ wpa_printf(MSG_WARNING,
+ "nl80211: Failed to add interface %s into bridge %s: %s",
+ bss->ifname, bss->brname, strerror(errno));
+ }
+ }
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
+{
+ return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
+}
+
+
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
+ struct hostapd_freq_params *freq)
+{
+ return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
+ freq);
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ if (drv->extended_capa && drv->extended_capa_mask) {
+ capa->extended_capa = drv->extended_capa;
+ capa->extended_capa_mask = drv->extended_capa_mask;
+ capa->extended_capa_len = drv->extended_capa_len;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
+ bss->ifname, drv->operstate, state,
+ state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nl80211_sta_flag_update upd;
+ int ret;
+
+ if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
+ wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+ MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (authorized)
+ upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
+ nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (!ret)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+ struct i802_bss *bss = priv;
+ return nl80211_set_channel(bss, freq, 0);
+}
+
+
+static inline int min_int(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+
+static int get_key_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the key index and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending key notifications.
+ */
+
+ if (tb[NL80211_ATTR_KEY_SEQ])
+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+ nl80211_nlmsg_clear(msg);
+ return NL_SKIP;
+}
+
+
+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
+ NL80211_CMD_GET_KEY);
+ if (!msg ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ memset(seq, 0, 6);
+
+ return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
+}
+
+
+static int i802_set_rts(void *priv, int rts)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ u32 val;
+
+ if (rts >= 2347 || rts == -1)
+ val = (u32) -1;
+ else
+ val = rts;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (!ret)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
+ "%d (%s)", rts, ret, strerror(-ret));
+ return ret;
+}
+
+
+static int i802_set_frag(void *priv, int frag)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ u32 val;
+
+ if (frag >= 2346 || frag == -1)
+ val = (u32) -1;
+ else
+ val = frag;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (!ret)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
+ "%d: %d (%s)", frag, ret, strerror(-ret));
+ return ret;
+}
+
+
+static int i802_flush(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
+ bss->ifname);
+
+ /*
+ * XXX: FIX! this needs to flush all VLANs too
+ */
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+ res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
+ "(%s)", res, strerror(-res));
+ }
+ return res;
+}
+
+
+static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
+ struct nlattr *attr)
+{
+ struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
+ struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
+ static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
+ [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
+ [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
+ };
+ int rem;
+
+ nla_for_each_nested(tidattr, attr, rem) {
+ if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
+ tidattr, NULL) != 0 ||
+ !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
+ nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
+ tid_stats[NL80211_TID_STATS_TXQ_STATS],
+ txq_stats_policy) != 0)
+ continue;
+ /* sum the backlogs over all TIDs for station */
+ if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
+ data->backlog_bytes += nla_get_u32(
+ txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
+ if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
+ data->backlog_bytes += nla_get_u32(
+ txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
+ }
+}
+
+
+static int get_sta_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct hostap_sta_driver_data *data = arg;
+ struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
+ };
+ struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
+ static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+ [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+ [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
+ [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+ [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending station notifications.
+ */
+
+ if (!tb[NL80211_ATTR_STA_INFO]) {
+ wpa_printf(MSG_DEBUG, "sta stats missing!");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
+ tb[NL80211_ATTR_STA_INFO],
+ stats_policy)) {
+ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ if (stats[NL80211_STA_INFO_INACTIVE_TIME])
+ data->inactive_msec =
+ nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
+ /* For backwards compatibility, fetch the 32-bit counters first. */
+ if (stats[NL80211_STA_INFO_RX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
+ if (stats[NL80211_STA_INFO_TX_BYTES])
+ data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
+ if (stats[NL80211_STA_INFO_RX_BYTES64] &&
+ stats[NL80211_STA_INFO_TX_BYTES64]) {
+ /*
+ * The driver supports 64-bit counters, so use them to override
+ * the 32-bit values.
+ */
+ data->rx_bytes =
+ nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
+ data->tx_bytes =
+ nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
+ data->bytes_64bit = 1;
+ }
+ if (stats[NL80211_STA_INFO_RX_PACKETS])
+ data->rx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
+ if (stats[NL80211_STA_INFO_TX_PACKETS])
+ data->tx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+ if (stats[NL80211_STA_INFO_RX_DURATION])
+ data->rx_airtime =
+ nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
+ if (stats[NL80211_STA_INFO_TX_DURATION])
+ data->tx_airtime =
+ nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
+ if (stats[NL80211_STA_INFO_TX_FAILED])
+ data->tx_retry_failed =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
+ if (stats[NL80211_STA_INFO_SIGNAL])
+ data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
+ if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
+ data->last_ack_rssi =
+ nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
+ data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
+ }
+
+ if (stats[NL80211_STA_INFO_TX_BITRATE] &&
+ nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
+ stats[NL80211_STA_INFO_TX_BITRATE],
+ rate_policy) == 0) {
+ if (rate[NL80211_RATE_INFO_BITRATE32])
+ data->current_tx_rate =
+ nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+ else if (rate[NL80211_RATE_INFO_BITRATE])
+ data->current_tx_rate =
+ nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+ if (rate[NL80211_RATE_INFO_MCS]) {
+ data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+ data->flags |= STA_DRV_DATA_TX_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+ data->tx_vhtmcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+ data->flags |= STA_DRV_DATA_TX_VHT_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_SHORT_GI])
+ data->flags |= STA_DRV_DATA_TX_SHORT_GI;
+ if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+ data->tx_vht_nss =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+ data->flags |= STA_DRV_DATA_TX_VHT_NSS;
+ }
+ }
+
+ if (stats[NL80211_STA_INFO_RX_BITRATE] &&
+ nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
+ stats[NL80211_STA_INFO_RX_BITRATE],
+ rate_policy) == 0) {
+ if (rate[NL80211_RATE_INFO_BITRATE32])
+ data->current_rx_rate =
+ nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+ else if (rate[NL80211_RATE_INFO_BITRATE])
+ data->current_rx_rate =
+ nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+ if (rate[NL80211_RATE_INFO_MCS]) {
+ data->rx_mcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+ data->flags |= STA_DRV_DATA_RX_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+ data->rx_vhtmcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+ data->flags |= STA_DRV_DATA_RX_VHT_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_SHORT_GI])
+ data->flags |= STA_DRV_DATA_RX_SHORT_GI;
+ if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+ data->rx_vht_nss =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+ data->flags |= STA_DRV_DATA_RX_VHT_NSS;
+ }
+ }
+
+ if (stats[NL80211_STA_INFO_TID_STATS])
+ get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
+
+ return NL_SKIP;
+}
+
+static int i802_read_sta_data(struct i802_bss *bss,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct nl_msg *msg;
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
+ NULL, NULL);
+}
+
+
+static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *txq, *params;
+ int res;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
+ if (!msg)
+ return -1;
+
+ txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
+ if (!txq)
+ goto fail;
+
+ /* We are only sending parameters for a single TXQ at a time */
+ params = nla_nest_start(msg, 1);
+ if (!params)
+ goto fail;
+
+ switch (queue) {
+ case 0:
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
+ goto fail;
+ break;
+ case 1:
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
+ goto fail;
+ break;
+ case 2:
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
+ goto fail;
+ break;
+ case 3:
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
+ goto fail;
+ break;
+ }
+ /* Burst time is configured in units of 0.1 msec and TXOP parameter in
+ * 32 usec, so need to convert the value here. */
+ if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
+ (burst_time * 100 + 16) / 32) ||
+ nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
+ nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
+ nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ nla_nest_end(msg, txq);
+
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
+ queue, aifs, cw_min, cw_max, burst_time, res);
+ if (res == 0)
+ return 0;
+ msg = NULL;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
+ ", ifname=%s[%d], vlan_id=%d)",
+ bss->ifname, if_nametoindex(bss->ifname),
+ MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+ nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
+ nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
+ MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
+ MAC2STR(addr), ifname, vlan_id, ret,
+ strerror(-ret));
+ }
+ return ret;
+}
+
+
+static int i802_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_sta_driver_data data;
+ int ret;
+
+ os_memset(&data, 0, sizeof(data));
+ data.inactive_msec = (unsigned long) -1;
+ ret = i802_read_sta_data(priv, &data, addr);
+ if (ret == -ENOENT)
+ return -ENOENT;
+ if (ret || data.inactive_msec == (unsigned long) -1)
+ return -1;
+ return data.inactive_msec / 1000;
+}
+
+
+static int i802_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if 0
+ /* TODO */
+#endif
+ return 0;
+}
+
+
+static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+ u16 reason)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_mgmt mgmt;
+ u8 channel;
+
+ if (ieee80211_freq_to_chan(bss->freq, &channel) ==
+ HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ return i802_sta_disassoc(priv, own_addr, addr, reason);
+ }
+
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
+ if (drv->device_ap_sme)
+ return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+ 0, NULL, 0, 0);
+}
+
+
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ u16 reason)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ieee80211_mgmt mgmt;
+
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
+ if (drv->device_ap_sme)
+ return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+ 0, NULL, 0, 0);
+}
+
+
+static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
+{
+ char buf[200], *pos, *end;
+ int i, res;
+
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (!drv->if_indices[i].ifindex)
+ continue;
+ res = os_snprintf(pos, end - pos, " %d(%d)",
+ drv->if_indices[i].ifindex,
+ drv->if_indices[i].reason);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+
+ wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
+ drv->num_if_indices, buf);
+}
+
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason)
+{
+ int i;
+ struct drv_nl80211_if_info *old;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
+ ifidx, ifidx_reason);
+ if (have_ifidx(drv, ifidx, ifidx_reason)) {
+ wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
+ ifidx);
+ return;
+ }
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i].ifindex == 0) {
+ drv->if_indices[i].ifindex = ifidx;
+ drv->if_indices[i].reason = ifidx_reason;
+ dump_ifidx(drv);
+ return;
+ }
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ old = drv->if_indices;
+ else
+ old = NULL;
+
+ drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+ sizeof(*old));
+ if (!drv->if_indices) {
+ if (!old)
+ drv->if_indices = drv->default_if_indices;
+ else
+ drv->if_indices = old;
+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+ "interfaces");
+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+ return;
+ }
+ if (!old)
+ os_memcpy(drv->if_indices, drv->default_if_indices,
+ sizeof(drv->default_if_indices));
+ drv->if_indices[drv->num_if_indices].ifindex = ifidx;
+ drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
+ drv->num_if_indices++;
+ dump_ifidx(drv);
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if ((drv->if_indices[i].ifindex == ifidx ||
+ ifidx == IFIDX_ANY) &&
+ (drv->if_indices[i].reason == ifidx_reason ||
+ ifidx_reason == IFIDX_ANY)) {
+ drv->if_indices[i].ifindex = 0;
+ drv->if_indices[i].reason = 0;
+ break;
+ }
+ }
+ dump_ifidx(drv);
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+ int ifidx_reason)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++)
+ if (drv->if_indices[i].ifindex == ifidx &&
+ (drv->if_indices[i].reason == ifidx_reason ||
+ ifidx_reason == IFIDX_ANY))
+ return 1;
+
+ return 0;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+ const char *bridge_ifname, char *ifname_wds)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ char name[IFNAMSIZ + 1];
+ union wpa_event_data event;
+ int ret;
+
+ ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ if (ret >= (int) sizeof(name))
+ wpa_printf(MSG_WARNING,
+ "nl80211: WDS interface name was truncated");
+ else if (ret < 0)
+ return ret;
+
+ if (ifname_wds)
+ os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+ " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+ if (val) {
+ if (!if_nametoindex(name)) {
+ if (nl80211_create_iface(drv, name,
+ NL80211_IFTYPE_AP_VLAN,
+ bss->addr, 1, NULL, NULL, 0) <
+ 0)
+ return -1;
+ if (bridge_ifname &&
+ linux_br_add_if(drv->global->ioctl_sock,
+ bridge_ifname, name) < 0)
+ return -1;
+
+ os_memset(&event, 0, sizeof(event));
+ event.wds_sta_interface.sta_addr = addr;
+ event.wds_sta_interface.ifname = name;
+ event.wds_sta_interface.istatus = INTERFACE_ADDED;
+ wpa_supplicant_event(bss->ctx,
+ EVENT_WDS_STA_INTERFACE_STATUS,
+ &event);
+ }
+ if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+ "interface %s up", name);
+ }
+ return i802_set_sta_vlan(priv, addr, name, 0);
+ } else {
+ if (bridge_ifname &&
+ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+ name) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to remove interface %s from bridge %s: %s",
+ name, bridge_ifname, strerror(errno));
+
+ i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+ nl80211_remove_iface(drv, if_nametoindex(name));
+ os_memset(&event, 0, sizeof(event));
+ event.wds_sta_interface.sta_addr = addr;
+ event.wds_sta_interface.ifname = name;
+ event.wds_sta_interface.istatus = INTERFACE_REMOVED;
+ wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+ &event);
+ return 0;
+ }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ struct sockaddr_ll lladdr;
+ unsigned char buf[3000];
+ int len;
+ socklen_t fromlen = sizeof(lladdr);
+
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&lladdr, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
+ drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
+static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
+ const char *brname, const char *ifname)
+{
+ int br_ifindex;
+ char in_br[IFNAMSIZ];
+
+ os_strlcpy(bss->brname, brname, IFNAMSIZ);
+ br_ifindex = if_nametoindex(brname);
+ if (br_ifindex == 0) {
+ /*
+ * Bridge was configured, but the bridge device does
+ * not exist. Try to add it now.
+ */
+ if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
+ "bridge interface %s: %s",
+ brname, strerror(errno));
+ return -1;
+ }
+ bss->added_bridge = 1;
+ br_ifindex = if_nametoindex(brname);
+ add_ifidx(drv, br_ifindex, drv->ifindex);
+ }
+ bss->br_ifindex = br_ifindex;
+
+ if (linux_br_get(in_br, ifname) == 0) {
+ if (os_strcmp(in_br, brname) == 0) {
+ bss->already_in_bridge = 1;
+ return 0; /* already in the bridge */
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
+ "bridge %s", ifname, in_br);
+ if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+ 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to "
+ "remove interface %s from bridge "
+ "%s: %s",
+ ifname, in_br, strerror(errno));
+ return -1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
+ ifname, brname);
+ if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
+ wpa_printf(MSG_WARNING,
+ "nl80211: Failed to add interface %s into bridge %s: %s",
+ ifname, brname, strerror(errno));
+ /* Try to continue without the interface being in a bridge. This
+ * may be needed for some cases, e.g., with Open vSwitch, where
+ * an external component will need to handle bridge
+ * configuration. */
+ return 0;
+ }
+ bss->added_if_into_bridge = 1;
+
+ return 0;
+}
+
+
+static void *i802_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *bss;
+ size_t i;
+ char master_ifname[IFNAMSIZ];
+ int ifindex, br_ifindex = 0;
+ int br_added = 0;
+
+ bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+ params->global_priv, 1,
+ params->bssid, params->driver_params);
+ if (bss == NULL)
+ return NULL;
+
+ drv = bss->drv;
+
+ if (linux_br_get(master_ifname, params->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
+ 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), drv->ifindex);
+
+ /* check if master itself is under bridge */
+ if (linux_br_get(master_ifname, master_ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
+ master_ifname);
+ br_ifindex = if_nametoindex(master_ifname);
+ os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+ }
+ } else {
+ master_ifname[0] = '\0';
+ }
+
+ bss->br_ifindex = br_ifindex;
+
+ for (i = 0; i < params->num_bridge; i++) {
+ if (params->bridge[i]) {
+ ifindex = if_nametoindex(params->bridge[i]);
+ if (ifindex)
+ add_ifidx(drv, ifindex, drv->ifindex);
+ if (ifindex == br_ifindex)
+ br_added = 1;
+ }
+ }
+
+ /* start listening for EAPOL on the default AP interface */
+ add_ifidx(drv, drv->ifindex, IFIDX_ANY);
+
+ if (params->num_bridge && params->bridge[0]) {
+ if (i802_check_bridge(drv, bss, params->bridge[0],
+ params->ifname) < 0)
+ goto failed;
+ if (os_strcmp(params->bridge[0], master_ifname) != 0)
+ br_added = 1;
+ }
+
+ if (!br_added && br_ifindex &&
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex, drv->ifindex);
+
+#ifdef CONFIG_LIBNL3_ROUTE
+ if (bss->added_if_into_bridge || bss->already_in_bridge) {
+ int err;
+
+ drv->rtnl_sk = nl_socket_alloc();
+ if (drv->rtnl_sk == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
+ goto failed;
+ }
+
+ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
+ if (err) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
+ nl_geterror(err));
+ goto failed;
+ }
+ }
+#endif /* CONFIG_LIBNL3_ROUTE */
+
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Do not open EAPOL RX socket - using control port for RX");
+ goto skip_eapol_sock;
+ }
+
+ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
+ if (drv->eapol_sock < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+ strerror(errno));
+ goto failed;
+ }
+
+ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
+ {
+ wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
+ goto failed;
+ }
+skip_eapol_sock:
+
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ params->own_addr))
+ goto failed;
+ os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
+
+ memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
+ return bss;
+
+failed:
+ wpa_driver_nl80211_deinit(bss);
+ return NULL;
+}
+
+
+static void i802_deinit(void *priv)
+{
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
+}
+
+
+static enum nl80211_iftype wpa_driver_nl80211_if_type(
+ enum wpa_driver_if_type type)
+{
+ switch (type) {
+ case WPA_IF_STATION:
+ return NL80211_IFTYPE_STATION;
+ case WPA_IF_P2P_CLIENT:
+ case WPA_IF_P2P_GROUP:
+ return NL80211_IFTYPE_P2P_CLIENT;
+ case WPA_IF_AP_VLAN:
+ return NL80211_IFTYPE_AP_VLAN;
+ case WPA_IF_AP_BSS:
+ return NL80211_IFTYPE_AP;
+ case WPA_IF_P2P_GO:
+ return NL80211_IFTYPE_P2P_GO;
+ case WPA_IF_P2P_DEVICE:
+ return NL80211_IFTYPE_P2P_DEVICE;
+ case WPA_IF_MESH:
+ return NL80211_IFTYPE_MESH_POINT;
+ default:
+ return -1;
+ }
+}
+
+
+static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
+{
+ struct wpa_driver_nl80211_data *drv;
+ dl_list_for_each(drv, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
+{
+ unsigned int idx;
+
+ if (!drv->global)
+ return -1;
+
+ os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
+ for (idx = 0; idx < 64; idx++) {
+ new_addr[0] = drv->first_bss->addr[0] | 0x02;
+ new_addr[0] ^= idx << 2;
+ if (!nl80211_addr_in_use(drv->global, new_addr))
+ break;
+ }
+ if (idx == 64)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
+ MACSTR, MAC2STR(new_addr));
+
+ return 0;
+}
+
+
+struct wdev_info {
+ u64 wdev_id;
+ int wdev_id_set;
+ u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wdev_info *wi = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_WDEV]) {
+ wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wi->wdev_id_set = 1;
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, const u8 *addr,
+ void *bss_ctx, void **drv_priv,
+ char *force_ifname, u8 *if_addr,
+ const char *bridge, int use_existing,
+ int setup_ap)
+{
+ enum nl80211_iftype nlmode;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifidx;
+ int added = 1;
+
+ if (addr)
+ os_memcpy(if_addr, addr, ETH_ALEN);
+ nlmode = wpa_driver_nl80211_if_type(type);
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ struct wdev_info p2pdev_info;
+
+ os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+ ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+ 0, nl80211_wdev_handler,
+ &p2pdev_info, use_existing);
+ if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+ ifname);
+ return -1;
+ }
+
+ drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+ drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+ if (!is_zero_ether_addr(p2pdev_info.macaddr))
+ os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+ ifname,
+ (long long unsigned int) p2pdev_info.wdev_id);
+ } else {
+ ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+ 0, NULL, NULL, use_existing);
+ if (use_existing && ifidx == -ENFILE) {
+ added = 0;
+ ifidx = if_nametoindex(ifname);
+ } else if (ifidx < 0) {
+ return -1;
+ }
+ }
+
+ if (!addr) {
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ os_memcpy(if_addr, bss->addr, ETH_ALEN);
+ else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+ ifname, if_addr) < 0) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ }
+
+ if (!addr &&
+ (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
+ 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,
+ new_addr) < 0) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ if (nl80211_addr_in_use(drv->global, new_addr)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
+ "for interface %s type %d", ifname, type);
+ if (nl80211_vif_addr(drv, new_addr) < 0) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+ new_addr) < 0) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ }
+ os_memcpy(if_addr, new_addr, ETH_ALEN);
+ }
+
+ if (type == WPA_IF_AP_BSS && setup_ap) {
+ struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+ if (new_bss == NULL) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+
+ if (bridge &&
+ i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+ "interface %s to a bridge %s",
+ ifname, bridge);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ os_free(new_bss);
+ return -1;
+ }
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+ {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ os_free(new_bss);
+ return -1;
+ }
+ os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+ os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
+ new_bss->ifindex = ifidx;
+ new_bss->drv = drv;
+ new_bss->next = drv->first_bss->next;
+ new_bss->freq = drv->first_bss->freq;
+ new_bss->ctx = bss_ctx;
+ new_bss->added_if = added;
+ drv->first_bss->next = new_bss;
+ if (drv_priv)
+ *drv_priv = new_bss;
+ nl80211_init_bss(new_bss);
+
+ /* Subscribe management frames for this WPA_IF_AP_BSS */
+ if (nl80211_setup_ap(new_bss))
+ return -1;
+ }
+
+ if (drv->global)
+ drv->global->if_add_ifindex = ifidx;
+
+ /*
+ * Some virtual interfaces need to process EAPOL packets and events on
+ * the parent interface. This is used mainly with hostapd.
+ */
+ if (ifidx > 0 &&
+ (drv->hostapd ||
+ nlmode == NL80211_IFTYPE_AP_VLAN ||
+ nlmode == NL80211_IFTYPE_WDS ||
+ nlmode == NL80211_IFTYPE_MONITOR))
+ add_ifidx(drv, ifidx, IFIDX_ANY);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
+ enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ifindex = if_nametoindex(ifname);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+ __func__, type, ifname, ifindex, bss->added_if);
+ if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
+ nl80211_remove_iface(drv, ifindex);
+ else if (ifindex > 0 && !bss->added_if) {
+ struct wpa_driver_nl80211_data *drv2;
+ dl_list_for_each(drv2, &drv->global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ del_ifidx(drv2, ifindex, IFIDX_ANY);
+ del_ifidx(drv2, IFIDX_ANY, ifindex);
+ }
+ }
+
+ if (type != WPA_IF_AP_BSS)
+ return 0;
+
+ if (bss->added_if_into_bridge) {
+ if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "interface %s from bridge %s: %s",
+ bss->ifname, bss->brname, strerror(errno));
+ }
+ if (bss->added_bridge) {
+ if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "bridge %s: %s",
+ bss->brname, strerror(errno));
+ }
+
+ if (bss != drv->first_bss) {
+ struct i802_bss *tbss;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
+ for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
+ if (tbss->next == bss) {
+ tbss->next = bss->next;
+ /* Unsubscribe management frames */
+ nl80211_teardown_ap(bss);
+ nl80211_destroy_bss(bss);
+ if (!bss->added_if)
+ i802_set_iface_flags(bss, 0);
+ os_free(bss);
+ bss = NULL;
+ break;
+ }
+ }
+ if (bss)
+ wpa_printf(MSG_INFO, "nl80211: %s - could not find "
+ "BSS %p in the list", __func__, bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+ nl80211_teardown_ap(bss);
+ if (!bss->added_if && !drv->first_bss->next)
+ wpa_driver_nl80211_del_beacon(bss);
+ nl80211_destroy_bss(bss);
+ if (!bss->added_if)
+ i802_set_iface_flags(bss, 0);
+ if (drv->first_bss->next) {
+ drv->first_bss = drv->first_bss->next;
+ drv->ctx = drv->first_bss->ctx;
+ os_free(bss);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
+ }
+ }
+
+ return 0;
+}
+
+
+static int cookie_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u64 *cookie = arg;
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_COOKIE])
+ *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ return NL_SKIP;
+}
+
+
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+ unsigned int freq, unsigned int wait,
+ const u8 *buf, size_t buf_len,
+ int save_cookie, int no_cck, int no_ack,
+ int offchanok, const u16 *csa_offs,
+ size_t csa_offs_len)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ u64 cookie;
+ int ret = -1;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+ "no_ack=%d offchanok=%d",
+ freq, wait, no_cck, no_ack, offchanok);
+ wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+ (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+ (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
+ (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+ drv->test_use_roc_tx) &&
+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
+ (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
+ (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
+ (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
+ csa_offs_len * sizeof(u16), csa_offs)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
+ goto fail;
+
+ cookie = 0;
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
+ "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
+ freq, wait);
+ } else {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
+ "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+ (long long unsigned int) cookie);
+
+ if (save_cookie)
+ drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
+
+ if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Drop oldest pending send frame cookie 0x%llx",
+ (long long unsigned int)
+ drv->send_frame_cookies[0]);
+ os_memmove(&drv->send_frame_cookies[0],
+ &drv->send_frame_cookies[1],
+ (MAX_SEND_FRAME_COOKIES - 1) *
+ sizeof(u64));
+ drv->num_send_frame_cookies--;
+ }
+ drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
+ drv->num_send_frame_cookies++;
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+ unsigned int freq,
+ unsigned int wait_time,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ int no_cck)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ u8 *buf;
+ struct ieee80211_hdr *hdr;
+ int offchanok = 1;
+
+ if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
+ bss->beacon_set)
+ offchanok = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
+ "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
+ drv->ifindex, freq, wait_time, no_cck, offchanok);
+
+ buf = os_zalloc(24 + data_len);
+ if (buf == NULL)
+ return ret;
+ os_memcpy(buf + 24, data, data_len);
+ hdr = (struct ieee80211_hdr *) buf;
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+ os_memcpy(hdr->addr1, dst, ETH_ALEN);
+ os_memcpy(hdr->addr2, src, ETH_ALEN);
+ os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+
+ if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
+ MAC2STR(src));
+ os_memcpy(bss->rand_addr, src, ETH_ALEN);
+ } else {
+ os_memset(bss->rand_addr, 0, ETH_ALEN);
+ }
+
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode)) {
+ struct hostapd_hw_modes *modes;
+ u16 num_modes, flags;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(bss, &num_modes,
+ &flags, &dfs_domain);
+ if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
+ ieee80211_is_dfs(bss->freq, modes, num_modes))
+ offchanok = 0;
+ if (modes) {
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+ os_free(modes);
+ }
+ }
+#endif /* CONFIG_MESH */
+
+ if (is_ap_interface(drv->nlmode) &&
+ (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+ (int) freq == bss->freq || drv->device_ap_sme ||
+ !drv->use_monitor))
+ ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
+ 0, freq, no_cck, offchanok,
+ wait_time, NULL, 0, 0);
+ else
+ ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
+ 24 + data_len,
+ 1, no_cck, 0, offchanok, NULL, 0);
+
+ os_free(buf);
+ return ret;
+}
+
+
+static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
+ (long long unsigned int) cookie);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+}
+
+
+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ unsigned int i;
+ u64 cookie;
+
+ /* Cancel the last pending TX cookie */
+ nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
+
+ /*
+ * Cancel the other pending TX cookies, if any. This is needed since
+ * the driver may keep a list of all pending offchannel TX operations
+ * and free up the radio only once they have expired or cancelled.
+ */
+ for (i = drv->num_send_frame_cookies; i > 0; i--) {
+ cookie = drv->send_frame_cookies[i - 1];
+ if (cookie != drv->send_frame_cookie)
+ nl80211_frame_wait_cancel(bss, cookie);
+ }
+ drv->num_send_frame_cookies = 0;
+}
+
+
+static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
+ unsigned int duration)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ u64 cookie;
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ cookie = 0;
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
+ "0x%llx for freq=%u MHz duration=%u",
+ (long long unsigned int) cookie, freq, duration);
+ drv->remain_on_chan_cookie = cookie;
+ drv->pending_remain_on_chan = 1;
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
+ "(freq=%d duration=%u): %d (%s)",
+ freq, duration, ret, strerror(-ret));
+ return -1;
+}
+
+
+static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->pending_remain_on_chan) {
+ wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
+ "to cancel");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
+ "0x%llx",
+ (long long unsigned int) drv->remain_on_chan_cookie);
+
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
+ if (!msg ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
+ "%d (%s)", ret, strerror(-ret));
+ return -1;
+}
+
+
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (!report) {
+ if (bss->nl_preq && drv->device_ap_sme &&
+ is_ap_interface(drv->nlmode) && !bss->in_deinit &&
+ !bss->static_ap) {
+ /*
+ * Do not disable Probe Request reporting that was
+ * enabled in nl80211_setup_ap().
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+ "Probe Request reporting nl_preq=%p while "
+ "in AP mode", bss->nl_preq);
+ } else if (bss->nl_preq) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
+ "reporting nl_preq=%p", bss->nl_preq);
+ nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
+ }
+ return 0;
+ }
+
+ if (bss->nl_preq) {
+ wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
+ "already on! nl_preq=%p", bss->nl_preq);
+ return 0;
+ }
+
+ bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+ if (bss->nl_preq == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+ "reporting nl_preq=%p", bss->nl_preq);
+
+ if (nl80211_register_frame(bss, bss->nl_preq,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_PROBE_REQ << 4),
+ NULL, 0, false) < 0)
+ goto out_err;
+
+ nl80211_register_eloop_read(&bss->nl_preq,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb, 0);
+
+ return 0;
+
+ out_err:
+ nl_destroy_handles(&bss->nl_preq);
+ return -1;
+}
+
+
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int disabled)
+{
+ struct nl_msg *msg;
+ struct nlattr *bands, *band;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
+ ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
+ "no NL80211_TXRATE_LEGACY constraint");
+
+ msg = nl80211_ifindex_msg(drv, ifindex, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK);
+ if (!msg)
+ return -1;
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ goto fail;
+
+ /*
+ * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
+ * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
+ * rates. All 5 GHz rates are left enabled.
+ */
+ band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ if (!band ||
+ (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
+ goto fail;
+ nla_nest_end(msg, band);
+
+ nla_nest_end(msg, bands);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ } else
+ drv->disabled_11b_rates = disabled;
+
+ return ret;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int wpa_driver_nl80211_deinit_ap(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!is_ap_interface(drv->nlmode))
+ return -1;
+ wpa_driver_nl80211_del_beacon(bss);
+ bss->beacon_set = 0;
+
+ /*
+ * If the P2P GO interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
+ return 0;
+
+ return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
+static int wpa_driver_nl80211_stop_ap(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!is_ap_interface(drv->nlmode))
+ return -1;
+ wpa_driver_nl80211_del_beacon(bss);
+ bss->beacon_set = 0;
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
+ return -1;
+
+ /*
+ * If the P2P Client interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (bss->if_dynamic)
+ return 0;
+
+ return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
+static void wpa_driver_nl80211_resume(void *priv)
+{
+ struct i802_bss *bss = priv;
+ enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
+
+ if (i802_set_iface_flags(bss, 1))
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
+
+ if (is_p2p_net_interface(nlmode))
+ nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
+}
+
+
+static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *cqm;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
+ "hysteresis=%d", threshold, hysteresis);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
+ !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, cqm);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_signal_info *sig_change = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ sig_change->center_frq1 = -1;
+ sig_change->center_frq2 = -1;
+ sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+ sig_change->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ sig_change->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ sig_change->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
+}
+
+
+static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int res;
+
+ os_memset(si, 0, sizeof(*si));
+ res = nl80211_get_link_signal(drv, si);
+ if (res) {
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
+ drv->nlmode != NL80211_IFTYPE_MESH_POINT)
+ return res;
+ si->current_signal = 0;
+ }
+
+ res = nl80211_get_channel_width(drv, si);
+ if (res != 0)
+ return res;
+
+ return nl80211_get_link_noise(drv, si);
+}
+
+
+static int nl80211_set_param(void *priv, const char *param)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (param == NULL)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
+
+#ifdef CONFIG_P2P
+ if (os_strstr(param, "use_p2p_group_interface=1")) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+#endif /* CONFIG_P2P */
+
+ if (os_strstr(param, "use_monitor=1"))
+ drv->use_monitor = 1;
+
+ if (os_strstr(param, "force_connect_cmd=1")) {
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
+ drv->force_connect_cmd = 1;
+ }
+
+ if (os_strstr(param, "force_bss_selection=1"))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+
+ if (os_strstr(param, "no_offchannel_tx=1")) {
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ drv->test_use_roc_tx = 1;
+ }
+
+ if (os_strstr(param, "control_port=0")) {
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
+ drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
+ WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
+ drv->control_port_ap = 0;
+ }
+
+ if (os_strstr(param, "control_port_ap=1"))
+ drv->control_port_ap = 1;
+
+ if (os_strstr(param, "control_port_ap=0")) {
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
+ drv->control_port_ap = 0;
+ }
+
+ if (os_strstr(param, "full_ap_client_state=0"))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
+
+ if (os_strstr(param, "no_rrm=1")) {
+ drv->no_rrm = 1;
+
+ if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
+ !is_mesh_interface(drv->nlmode)) {
+ nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
+ if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to re-register Action frame processing - ignore for now");
+ }
+ }
+
+ return 0;
+}
+
+
+static void * nl80211_global_init(void *ctx)
+{
+ struct nl80211_global *global;
+ struct netlink_config *cfg;
+
+ global = os_zalloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
+ global->ctx = ctx;
+ global->ioctl_sock = -1;
+ dl_list_init(&global->interfaces);
+ global->if_add_ifindex = -1;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto err;
+
+ cfg->ctx = global;
+ cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+ global->netlink = netlink_init(cfg);
+ if (global->netlink == NULL) {
+ os_free(cfg);
+ goto err;
+ }
+
+ if (wpa_driver_nl80211_init_nl_global(global) < 0)
+ goto err;
+
+ global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (global->ioctl_sock < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+ strerror(errno));
+ goto err;
+ }
+
+ return global;
+
+err:
+ nl80211_global_deinit(global);
+ return NULL;
+}
+
+
+static void nl80211_global_deinit(void *priv)
+{
+ struct nl80211_global *global = priv;
+ if (global == NULL)
+ return;
+ if (!dl_list_empty(&global->interfaces)) {
+ wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
+ "nl80211_global_deinit",
+ dl_list_len(&global->interfaces));
+ }
+
+ if (global->netlink)
+ netlink_deinit(global->netlink);
+
+ nl_destroy_handles(&global->nl);
+
+ if (global->nl_event)
+ nl80211_destroy_eloop_handle(&global->nl_event, 0);
+
+ nl_cb_put(global->nl_cb);
+
+ if (global->ioctl_sock >= 0)
+ close(global->ioctl_sock);
+
+ os_free(global);
+}
+
+
+static const char * nl80211_get_radio_name(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ return drv->phyname;
+}
+
+
+static int nl80211_pmkid(struct i802_bss *bss, int cmd,
+ struct wpa_pmkid_params *params)
+{
+ struct nl_msg *msg;
+ const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
+
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ (params->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
+ (params->bssid &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
+ (params->ssid_len &&
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+ (params->fils_cache_id &&
+ nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
+ params->fils_cache_id)) ||
+ (params->pmk_lifetime &&
+ nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
+ params->pmk_lifetime)) ||
+ (params->pmk_reauth_threshold &&
+ nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+ params->pmk_reauth_threshold)) ||
+ (cmd != NL80211_CMD_DEL_PMKSA &&
+ params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
+ nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
+{
+ struct i802_bss *bss = priv;
+ int ret;
+
+ if (params->bssid)
+ wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
+ MAC2STR(params->bssid));
+ else if (params->fils_cache_id && params->ssid_len) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
+ params->fils_cache_id[0], params->fils_cache_id[1],
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ }
+
+ ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
+{
+ struct i802_bss *bss = priv;
+ int ret;
+
+ if (params->bssid)
+ wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+ MAC2STR(params->bssid));
+ else if (params->fils_cache_id && params->ssid_len) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
+ params->fils_cache_id[0], params->fils_cache_id[1],
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ }
+
+ ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
+ if (!msg)
+ return -ENOBUFS;
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static void clean_survey_results(struct survey_results *survey_results)
+{
+ struct freq_survey *survey, *tmp;
+
+ if (dl_list_empty(&survey_results->survey_list))
+ return;
+
+ dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+ struct freq_survey, list) {
+ dl_list_del(&survey->list);
+ os_free(survey);
+ }
+}
+
+
+static void add_survey(struct nlattr **sinfo, u32 ifidx,
+ struct dl_list *survey_list)
+{
+ struct freq_survey *survey;
+
+ survey = os_zalloc(sizeof(struct freq_survey));
+ if (!survey)
+ return;
+
+ survey->ifidx = ifidx;
+ survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ survey->filled = 0;
+
+ if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
+ survey->nf = (int8_t)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ survey->filled |= SURVEY_HAS_NF;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
+ survey->channel_time =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
+ survey->channel_time_busy =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
+ survey->channel_time_rx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
+ survey->channel_time_tx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
+ survey->freq,
+ survey->nf,
+ (unsigned long int) survey->channel_time,
+ (unsigned long int) survey->channel_time_busy,
+ (unsigned long int) survey->channel_time_tx,
+ (unsigned long int) survey->channel_time_rx,
+ survey->filled);
+
+ dl_list_add_tail(survey_list, &survey->list);
+}
+
+
+static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
+ unsigned int freq_filter)
+{
+ if (!freq_filter)
+ return 1;
+
+ return freq_filter == surveyed_freq;
+}
+
+
+static int survey_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ struct survey_results *survey_results;
+ u32 surveyed_freq = 0;
+ u32 ifidx;
+
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+
+ survey_results = (struct survey_results *) arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_IFINDEX])
+ return NL_SKIP;
+
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO])
+ return NL_SKIP;
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy))
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
+ wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
+ return NL_SKIP;
+ }
+
+ surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+
+ if (!check_survey_ok(sinfo, surveyed_freq,
+ survey_results->freq_filter))
+ return NL_SKIP;
+
+ if (survey_results->freq_filter &&
+ survey_results->freq_filter != surveyed_freq) {
+ wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
+ surveyed_freq);
+ return NL_SKIP;
+ }
+
+ add_survey(sinfo, ifidx, &survey_results->survey_list);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int err;
+ union wpa_event_data data;
+ struct survey_results *survey_results;
+
+ os_memset(&data, 0, sizeof(data));
+ survey_results = &data.survey_results;
+
+ dl_list_init(&survey_results->survey_list);
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ if (!msg)
+ return -ENOBUFS;
+
+ if (freq)
+ data.survey_results.freq_filter = freq;
+
+ do {
+ wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
+ err = send_and_recv_msgs(drv, msg, survey_handler,
+ survey_results, NULL, NULL);
+ } while (err > 0);
+
+ if (err)
+ wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
+ else
+ wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
+
+ clean_survey_results(survey_results);
+ return err;
+}
+
+
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
+ const u8 *replay_ctr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *replay_nested;
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->set_rekey_offload)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
+ !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
+ nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+ (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
+ nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+ replay_ctr)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return;
+ }
+
+ nla_nest_end(msg, replay_nested);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret == -EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver does not support rekey offload");
+ drv->set_rekey_offload = 0;
+ }
+}
+
+
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+ const u8 *addr, int qos)
+{
+ /* send data frame to poll STA and check whether
+ * this frame is ACKed */
+ struct {
+ struct ieee80211_hdr hdr;
+ u16 qos_ctl;
+ } STRUCT_PACKED nulldata;
+ size_t size;
+
+ /* Send data frame to poll STA and check whether this frame is ACKed */
+
+ os_memset(&nulldata, 0, sizeof(nulldata));
+
+ if (qos) {
+ nulldata.hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_QOS_NULL);
+ size = sizeof(nulldata);
+ } else {
+ nulldata.hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_NULLFUNC);
+ size = sizeof(struct ieee80211_hdr);
+ }
+
+ nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+ if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+ 0, 0, NULL, 0, 0) < 0)
+ wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+ "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+ int qos)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ u64 cookie;
+ int ret;
+
+ if (!drv->poll_command_supported) {
+ nl80211_send_null_frame(bss, own_addr, addr, qos);
+ return;
+ }
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
+ MACSTR " failed: ret=%d (%s)",
+ MAC2STR(addr), ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Client probe request addr=" MACSTR
+ " cookie=%llu", MAC2STR(addr),
+ (long long unsigned int) cookie);
+ }
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
+ nla_put_u32(msg, NL80211_ATTR_PS_STATE,
+ enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Setting PS state %s failed: %d (%s)",
+ enabled ? "enabled" : "disabled",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+ int ctwindow)
+{
+ struct i802_bss *bss = priv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+ "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+ if (opp_ps != -1 || ctwindow != -1) {
+#ifdef ANDROID_P2P
+ wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
+#else /* ANDROID_P2P */
+ return -1; /* Not yet supported */
+#endif /* ANDROID_P2P */
+ }
+
+ if (legacy_ps == -1)
+ return 0;
+ if (legacy_ps != 0 && legacy_ps != 1)
+ return -1; /* Not yet supported */
+
+ return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+static int nl80211_start_radar_detection(void *priv,
+ struct hostapd_freq_params *freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
+ freq->bandwidth, freq->center_freq1, freq->center_freq2);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+ "detection");
+ return -1;
+ }
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
+ nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret == 0)
+ return 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+ "%d (%s)", ret, strerror(-ret));
+ return -1;
+}
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_add_peer_capab(struct nl_msg *msg,
+ enum tdls_peer_capability capa)
+{
+ u32 peer_capab = 0;
+
+ if (!capa)
+ return 0;
+
+ if (capa & TDLS_PEER_HT)
+ peer_capab |= NL80211_TDLS_PEER_HT;
+ if (capa & TDLS_PEER_VHT)
+ peer_capab |= NL80211_TDLS_PEER_VHT;
+ if (capa & TDLS_PEER_WMM)
+ peer_capab |= NL80211_TDLS_PEER_WMM;
+ if (capa & TDLS_PEER_HE)
+ peer_capab |= NL80211_TDLS_PEER_HE;
+
+ return nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
+ peer_capab);
+}
+
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+ u8 dialog_token, u16 status_code,
+ u32 peer_capab, int initiator, const u8 *buf,
+ size_t len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
+ if (!dst)
+ return -EINVAL;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code) ||
+ nl80211_add_peer_capab(msg, peer_capab) ||
+ (initiator && nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
+ nla_put(msg, NL80211_ATTR_IE, len, buf))
+ goto fail;
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+
+fail:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ enum nl80211_tdls_operation nl80211_oper;
+ int res;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
+ switch (oper) {
+ case TDLS_DISCOVERY_REQ:
+ nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+ break;
+ case TDLS_SETUP:
+ nl80211_oper = NL80211_TDLS_SETUP;
+ break;
+ case TDLS_TEARDOWN:
+ nl80211_oper = NL80211_TDLS_TEARDOWN;
+ break;
+ case TDLS_ENABLE_LINK:
+ nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+ break;
+ case TDLS_DISABLE_LINK:
+ nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+ break;
+ case TDLS_ENABLE:
+ return 0;
+ case TDLS_DISABLE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
+ " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
+ strerror(-res));
+ return res;
+}
+
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+ " oper_class=%u freq=%u",
+ MAC2STR(addr), oper_class, params->freq);
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+ (ret = nl80211_put_freq_params(msg, params))) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+ return ret;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+ MAC2STR(addr));
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not build TDLS cancel chan switch");
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+#endif /* CONFIG TDLS */
+
+
+static int driver_nl80211_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
+{
+ struct i802_bss *bss = priv;
+
+ return wpa_driver_nl80211_set_key(bss, params);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+ struct wpa_driver_scan_params *params)
+{
+ struct i802_bss *bss = priv;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ /*
+ * Do a vendor specific scan if possible. If only_new_results is
+ * set, do a normal scan since a kernel (cfg80211) BSS cache flush
+ * cannot be achieved through a vendor scan. The below condition may
+ * need to be modified if new scan flags are added in the future whose
+ * functionality can only be achieved through a normal scan.
+ */
+ if (drv->scan_vendor_cmd_avail && !params->only_new_results)
+ return wpa_driver_nl80211_vendor_scan(bss, params);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ u16 reason_code)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+ struct wpa_driver_auth_params *params)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len, int noack,
+ unsigned int freq,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+ freq, 0, 0, wait, csa_offs,
+ csa_offs_len, no_encrypt);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
+}
+
+
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_bss *bss = priv;
+ return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+
+ os_memset(data, 0, sizeof(*data));
+ return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+ unsigned int wait_time,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ int no_cck)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+ bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
+static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
+ const u8 *ies, size_t ies_len)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 mdid = WPA_GET_LE16(md);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
+ nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
+ nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
+ "err=%d (%s)", ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
+ u16 reason_code, const u8 *ie, size_t ie_len)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
+ " reason %u", MAC2STR(peer_mac), reason_code);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
+ (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: update_dh_ie failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
+static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ return NULL;
+
+ return bss->addr;
+}
+
+
+static const char * scan_state_str(enum scan_states scan_state)
+{
+ switch (scan_state) {
+ case NO_SCAN:
+ return "NO_SCAN";
+ case SCAN_REQUESTED:
+ return "SCAN_REQUESTED";
+ case SCAN_STARTED:
+ return "SCAN_STARTED";
+ case SCAN_COMPLETED:
+ return "SCAN_COMPLETED";
+ case SCAN_ABORTED:
+ return "SCAN_ABORTED";
+ case SCHED_SCAN_STARTED:
+ return "SCHED_SCAN_STARTED";
+ case SCHED_SCAN_STOPPED:
+ return "SCHED_SCAN_STOPPED";
+ case SCHED_SCAN_RESULTS:
+ return "SCHED_SCAN_RESULTS";
+ }
+
+ return "??";
+}
+
+
+static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int res;
+ char *pos, *end;
+ struct nl_msg *msg;
+ char alpha2[3] = { 0, 0, 0 };
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "brname=%s\n"
+ "addr=" MACSTR "\n"
+ "freq=%d\n"
+ "%s%s%s%s%s%s",
+ bss->ifindex,
+ bss->ifname,
+ bss->brname,
+ MAC2STR(bss->addr),
+ bss->freq,
+ bss->beacon_set ? "beacon_set=1\n" : "",
+ bss->added_if_into_bridge ?
+ "added_if_into_bridge=1\n" : "",
+ bss->already_in_bridge ? "already_in_bridge=1\n" : "",
+ bss->added_bridge ? "added_bridge=1\n" : "",
+ bss->in_deinit ? "in_deinit=1\n" : "",
+ bss->if_dynamic ? "if_dynamic=1\n" : "");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ if (bss->wdev_id_set) {
+ res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
+ (unsigned long long) bss->wdev_id);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+
+ res = os_snprintf(pos, end - pos,
+ "phyname=%s\n"
+ "perm_addr=" MACSTR "\n"
+ "drv_ifindex=%d\n"
+ "operstate=%d\n"
+ "scan_state=%s\n"
+ "auth_bssid=" MACSTR "\n"
+ "auth_attempt_bssid=" MACSTR "\n"
+ "bssid=" MACSTR "\n"
+ "prev_bssid=" MACSTR "\n"
+ "associated=%d\n"
+ "assoc_freq=%u\n"
+ "monitor_sock=%d\n"
+ "monitor_ifidx=%d\n"
+ "monitor_refcount=%d\n"
+ "last_mgmt_freq=%u\n"
+ "eapol_tx_sock=%d\n"
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ drv->phyname,
+ MAC2STR(drv->perm_addr),
+ drv->ifindex,
+ drv->operstate,
+ scan_state_str(drv->scan_state),
+ MAC2STR(drv->auth_bssid),
+ MAC2STR(drv->auth_attempt_bssid),
+ MAC2STR(drv->bssid),
+ MAC2STR(drv->prev_bssid),
+ drv->associated,
+ drv->assoc_freq,
+ drv->monitor_sock,
+ drv->monitor_ifidx,
+ drv->monitor_refcount,
+ drv->last_mgmt_freq,
+ drv->eapol_tx_sock,
+ drv->ignore_if_down_event ?
+ "ignore_if_down_event=1\n" : "",
+ drv->scan_complete_events ?
+ "scan_complete_events=1\n" : "",
+ drv->disabled_11b_rates ?
+ "disabled_11b_rates=1\n" : "",
+ drv->pending_remain_on_chan ?
+ "pending_remain_on_chan=1\n" : "",
+ drv->in_interface_list ? "in_interface_list=1\n" : "",
+ drv->device_ap_sme ? "device_ap_sme=1\n" : "",
+ drv->poll_command_supported ?
+ "poll_command_supported=1\n" : "",
+ drv->data_tx_status ? "data_tx_status=1\n" : "",
+ drv->scan_for_auth ? "scan_for_auth=1\n" : "",
+ drv->retry_auth ? "retry_auth=1\n" : "",
+ drv->use_monitor ? "use_monitor=1\n" : "",
+ drv->ignore_next_local_disconnect ?
+ "ignore_next_local_disconnect=1\n" : "",
+ drv->ignore_next_local_deauth ?
+ "ignore_next_local_deauth=1\n" : "");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ if (drv->has_capability) {
+ res = os_snprintf(pos, end - pos,
+ "capa.key_mgmt=0x%x\n"
+ "capa.enc=0x%x\n"
+ "capa.auth=0x%x\n"
+ "capa.flags=0x%llx\n"
+ "capa.rrm_flags=0x%x\n"
+ "capa.max_scan_ssids=%d\n"
+ "capa.max_sched_scan_ssids=%d\n"
+ "capa.sched_scan_supported=%d\n"
+ "capa.max_match_sets=%d\n"
+ "capa.max_remain_on_chan=%u\n"
+ "capa.max_stations=%u\n"
+ "capa.probe_resp_offloads=0x%x\n"
+ "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.conc_capab=%u\n"
+ "capa.max_conc_chan_2_4=%u\n"
+ "capa.max_conc_chan_5_0=%u\n"
+ "capa.max_sched_scan_plans=%u\n"
+ "capa.max_sched_scan_plan_interval=%u\n"
+ "capa.max_sched_scan_plan_iterations=%u\n",
+ drv->capa.key_mgmt,
+ drv->capa.enc,
+ drv->capa.auth,
+ (unsigned long long) drv->capa.flags,
+ drv->capa.rrm_flags,
+ drv->capa.max_scan_ssids,
+ drv->capa.max_sched_scan_ssids,
+ drv->capa.sched_scan_supported,
+ drv->capa.max_match_sets,
+ drv->capa.max_remain_on_chan,
+ drv->capa.max_stations,
+ drv->capa.probe_resp_offloads,
+ 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.conc_capab,
+ drv->capa.max_conc_chan_2_4,
+ drv->capa.max_conc_chan_5_0,
+ drv->capa.max_sched_scan_plans,
+ drv->capa.max_sched_scan_plan_interval,
+ drv->capa.max_sched_scan_plan_iterations);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+
+ msg = nlmsg_alloc();
+ if (msg &&
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
+ if (send_and_recv_msgs(drv, msg, nl80211_get_country,
+ alpha2, NULL, NULL) == 0 &&
+ alpha2[0]) {
+ res = os_snprintf(pos, end - pos, "country=%s\n",
+ alpha2);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+ } else {
+ nlmsg_free(msg);
+ }
+
+ return pos - buf;
+}
+
+
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+ if ((settings->head &&
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD,
+ settings->head_len, settings->head)) ||
+ (settings->tail &&
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL,
+ settings->tail_len, settings->tail)) ||
+ (settings->beacon_ies &&
+ nla_put(msg, NL80211_ATTR_IE,
+ settings->beacon_ies_len, settings->beacon_ies)) ||
+ (settings->proberesp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ settings->proberesp_ies_len, settings->proberesp_ies)) ||
+ (settings->assocresp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ settings->assocresp_ies_len, settings->assocresp_ies)) ||
+ (settings->probe_resp &&
+ nla_put(msg, NL80211_ATTR_PROBE_RESP,
+ settings->probe_resp_len, settings->probe_resp)))
+ return -ENOBUFS;
+
+ return 0;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *beacon_csa;
+ int ret = -ENOBUFS;
+ int csa_off_len = 0;
+ int i;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d%s%s%s)",
+ settings->cs_count, settings->block_tx,
+ settings->freq_params.freq,
+ settings->freq_params.channel,
+ settings->freq_params.sec_channel_offset,
+ settings->freq_params.bandwidth,
+ settings->freq_params.center_freq1,
+ settings->freq_params.center_freq2,
+ settings->freq_params.ht_enabled ? " ht" : "",
+ settings->freq_params.vht_enabled ? " vht" : "",
+ settings->freq_params.he_enabled ? " he" : "");
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+ return -EOPNOTSUPP;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_AP &&
+ drv->nlmode != NL80211_IFTYPE_P2P_GO &&
+ drv->nlmode != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ /*
+ * Remove empty counters, assuming Probe Response and Beacon frame
+ * counters match. This implementation assumes that there are only two
+ * counters.
+ */
+ if (settings->counter_offset_beacon[0] &&
+ !settings->counter_offset_beacon[1]) {
+ csa_off_len = 1;
+ } else if (settings->counter_offset_beacon[1] &&
+ !settings->counter_offset_beacon[0]) {
+ csa_off_len = 1;
+ settings->counter_offset_beacon[0] =
+ settings->counter_offset_beacon[1];
+ settings->counter_offset_presp[0] =
+ settings->counter_offset_presp[1];
+ } else if (settings->counter_offset_beacon[1] &&
+ settings->counter_offset_beacon[0]) {
+ csa_off_len = 2;
+ } else {
+ wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
+ return -EINVAL;
+ }
+
+ /* Check CSA counters validity */
+ if (drv->capa.max_csa_counters &&
+ csa_off_len > drv->capa.max_csa_counters) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Too many CSA counters provided");
+ return -EINVAL;
+ }
+
+ if (!settings->beacon_csa.tail)
+ return -EINVAL;
+
+ for (i = 0; i < csa_off_len; i++) {
+ u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
+ u16 csa_c_off_presp = settings->counter_offset_presp[i];
+
+ if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
+ (settings->beacon_csa.tail[csa_c_off_bcn] !=
+ settings->cs_count))
+ return -EINVAL;
+
+ if (settings->beacon_csa.probe_resp &&
+ ((settings->beacon_csa.probe_resp_len <=
+ csa_c_off_presp) ||
+ (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
+ settings->cs_count)))
+ return -EINVAL;
+ }
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
+ nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
+ settings->cs_count) ||
+ (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
+ (settings->block_tx &&
+ nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
+ goto error;
+
+ /* beacon_after params */
+ ret = set_beacon_data(msg, &settings->beacon_after);
+ if (ret)
+ goto error;
+
+ /* beacon_csa params */
+ beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+ if (!beacon_csa)
+ goto fail;
+
+ ret = set_beacon_data(msg, &settings->beacon_csa);
+ if (ret)
+ goto error;
+
+ if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+ csa_off_len * sizeof(u16),
+ settings->counter_offset_beacon) ||
+ (settings->beacon_csa.probe_resp &&
+ nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+ csa_off_len * sizeof(u16),
+ settings->counter_offset_presp)))
+ goto fail;
+
+ nla_nest_end(msg, beacon_csa);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+
+fail:
+ ret = -ENOBUFS;
+error:
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+ return ret;
+}
+
+
+static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
+ u8 user_priority, u16 admitted_time)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
+ tsid, admitted_time, user_priority);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
+ nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int cmd_reply_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpabuf *buf = arg;
+
+ if (!buf)
+ return NL_SKIP;
+
+ if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
+ wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
+ return NL_SKIP;
+ }
+
+ wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0));
+
+ return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int vendor_reply_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *nl_vendor_reply, *nl;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpabuf *buf = arg;
+ int rem;
+
+ if (!buf)
+ return NL_SKIP;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
+
+ if (!nl_vendor_reply)
+ return NL_SKIP;
+
+ if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
+ wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
+ return NL_SKIP;
+ }
+
+ nla_for_each_nested(nl, nl_vendor_reply, rem) {
+ wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
+ }
+
+ return NL_SKIP;
+}
+
+
+static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
+ unsigned int subcmd)
+{
+ if (vendor_id != OUI_QCA)
+ return true;
+
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
+ case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
+ case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
+ case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
+ case QCA_NL80211_VENDOR_SUBCMD_NAN:
+ return false;
+ default:
+ return true;
+ }
+}
+
+
+static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
+ unsigned int subcmd, const u8 *data,
+ size_t data_len, enum nested_attr nested_attr,
+ struct wpabuf *buf)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret, nla_flag;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (vendor_id == 0xffffffff) {
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, subcmd);
+ if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
+ 0)
+ goto fail;
+ /* This test vendor_cmd can be used with nl80211 commands that
+ * need the connect nl_sock, so use the owner-setting variant
+ * of send_and_recv_msgs(). */
+ ret = send_and_recv_msgs_owner(drv, msg,
+ get_connect_handle(bss), 0,
+ cmd_reply_handler, buf,
+ NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
+ ret);
+ return ret;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (nested_attr == NESTED_ATTR_USED)
+ nla_flag = NLA_F_NESTED;
+ else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
+ is_cmd_with_nested_attrs(vendor_id, subcmd))
+ nla_flag = NLA_F_NESTED;
+ else
+ nla_flag = 0;
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
+ (data &&
+ nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
+ data_len, data)))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
+ NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
+ ret);
+ return ret;
+
+fail:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
+ u8 qos_map_set_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+ qos_map_set, qos_map_set_len);
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
+
+ return ret;
+}
+
+
+static int get_wowlan_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *wowlan_enabled = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_wowlan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int wowlan_enabled;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
+
+ ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
+ wowlan_enabled ? "enabled" : "disabled");
+
+ return wowlan_enabled;
+}
+
+
+static int nl80211_set_wowlan(void *priv,
+ const struct wowlan_triggers *triggers)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *wowlan_triggers;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
+ !(wowlan_triggers = nla_nest_start(msg,
+ NL80211_ATTR_WOWLAN_TRIGGERS)) ||
+ (triggers->any &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ (triggers->disconnect &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ (triggers->magic_pkt &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ (triggers->gtk_rekey_failure &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ (triggers->eap_identity_req &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ (triggers->four_way_handshake &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ (triggers->rfkill_release &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ nla_nest_end(msg, wowlan_triggers);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
+
+ return ret;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
+
+ if (!drv->roaming_vendor_cmd_avail) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
+ 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_ROAMING) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+ allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+ QCA_ROAMING_NOT_ALLOWED) ||
+ (bssid &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int nl80211_disable_fils(void *priv, int disable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ 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_SET_WIFI_CONFIGURATION) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
+ disable)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
+#define WPA_SUPPLICANT_CLIENT_ID 1
+
+static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
+ const u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params, *nlbssids, *attr;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
+ num_bssid);
+
+ if (!drv->roam_vendor_cmd_avail)
+ 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_ROAM) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
+ WPA_SUPPLICANT_CLIENT_ID) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
+ num_bssid))
+ goto fail;
+
+ nlbssids = nla_nest_start(
+ msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
+ if (!nlbssids)
+ goto fail;
+
+ for (i = 0; i < num_bssid; i++) {
+ attr = nla_nest_start(msg, i);
+ if (!attr)
+ goto fail;
+ if (nla_put(msg,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
+ ETH_ALEN, &bssid[i * ETH_ALEN]))
+ goto fail;
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
+ MAC2STR(&bssid[i * ETH_ALEN]));
+ nla_nest_end(msg, attr);
+ }
+ nla_nest_end(msg, nlbssids);
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ if (!drv->add_sta_node_vendor_cmd_avail)
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
+
+ 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_ADD_STA_NODE) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ (addr &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
+ addr)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
+ auth_alg)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
+static int nl80211_set_mac_addr(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int new_addr = addr != NULL;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (!addr)
+ addr = drv->perm_addr;
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
+ return -1;
+
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: failed to set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 1) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after failed set_mac_addr");
+ }
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ drv->addr_changed = new_addr;
+ os_memcpy(bss->addr, addr, ETH_ALEN);
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after set_mac_addr");
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_MESH
+
+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+ if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into mesh mode");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
+ size_t mesh_id_len)
+{
+ if (mesh_id) {
+ wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
+ wpa_ssid_txt(mesh_id, mesh_id_len));
+ return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
+ }
+
+ return 0;
+}
+
+
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct nlattr *container;
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ return -1;
+
+ if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+ nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ params->auto_plinks)) ||
+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ params->max_peer_links)) ||
+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
+ nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+ params->rssi_threshold)))
+ return -1;
+
+ /*
+ * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+ * the timer could disconnect stations even in that case.
+ */
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
+ nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+ params->peer_link_timeout)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+ return -1;
+ }
+
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
+ nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
+ return -1;
+ }
+
+ nla_nest_end(msg, container);
+
+ return 0;
+}
+
+
+static int nl80211_join_mesh(struct i802_bss *bss,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+ if (!msg ||
+ nl80211_put_freq_params(msg, &params->freq) ||
+ nl80211_put_basic_rates(msg, params->basic_rates) ||
+ nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
+ nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_dtim_period(msg, params->dtim_period))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+
+ if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+ if (!container)
+ goto fail;
+
+ if (params->ies) {
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
+ if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+ params->ies))
+ goto fail;
+ }
+ /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+ if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
+ goto fail;
+ }
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
+ goto fail;
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
+ goto fail;
+ nla_nest_end(msg, container);
+
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
+ if (nl80211_put_mesh_config(msg, &params->conf) < 0)
+ goto fail;
+
+ ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ ret = 0;
+ drv->assoc_freq = bss->freq = params->freq.freq;
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct i802_bss *bss = priv;
+ int ret, timeout;
+
+ timeout = params->conf.peer_link_timeout;
+
+ /* Disable kernel inactivity timer */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+ params->conf.peer_link_timeout = 0;
+
+ ret = nl80211_join_mesh(bss, params);
+ if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Mesh join retry for peer_link_timeout");
+ /*
+ * Old kernel does not support setting
+ * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
+ * into future from peer_link_timeout.
+ */
+ params->conf.peer_link_timeout = timeout + 60;
+ ret = nl80211_join_mesh(priv, params);
+ }
+
+ params->conf.peer_link_timeout = timeout;
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
+ ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 0);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: mesh leave request send successfully");
+ }
+
+ if (drv->start_mode_sta &&
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ NL80211_IFTYPE_STATION)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into station mode");
+ }
+ return ret;
+}
+
+
+static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
+ size_t len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
+ " failed: ret=%d (%s)",
+ MAC2STR(addr), ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
+ " probed successfully", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_MESH */
+
+
+static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr, int prefixlen,
+ const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr = NULL;
+ struct nl_addr *nl_lladdr = NULL;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr || prefixlen == 0 || !addr)
+ return -EINVAL;
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set before adding an ip neigh to it");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ /* set the corresponding lladdr for neigh */
+ nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
+ if (nl_lladdr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_lladdr);
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+ rtnl_neigh_set_state(rn, NUD_PERMANENT);
+
+ res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Adding bridge ip neigh failed: %s",
+ nl_geterror(res));
+ }
+errout:
+ if (nl_lladdr)
+ nl_addr_put(nl_lladdr);
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr)
+ return -EINVAL;
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set to delete an ip neigh");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+
+ res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Deleting bridge ip neigh failed: %s",
+ nl_geterror(res));
+ }
+errout:
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int linux_write_system_file(const char *path, unsigned int val)
+{
+ char buf[50];
+ int fd, len;
+
+ len = os_snprintf(buf, sizeof(buf), "%u\n", val);
+ if (os_snprintf_error(sizeof(buf), len))
+ return -1;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ if (write(fd, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to write Linux system file: %s with the value of %d",
+ path, val);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+
+static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
+{
+ switch (attr) {
+ case DRV_BR_PORT_ATTR_PROXYARP:
+ return "proxyarp_wifi";
+ case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
+ return "hairpin_mode";
+ }
+
+ return NULL;
+}
+
+
+static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ const char *attr_txt;
+
+ attr_txt = drv_br_port_attr_str(attr);
+ if (attr_txt == NULL)
+ return -EINVAL;
+
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
+ bss->ifname, attr_txt);
+
+ if (linux_write_system_file(path, val))
+ return -1;
+
+ return 0;
+}
+
+
+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;
+ }
+}
+
+
+static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ 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;
+
+ switch (param) {
+ case DRV_BR_NET_PARAM_GARP_ACCEPT:
+ ip_version = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ 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;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
+static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
+{
+ switch (hw_mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return QCA_ACS_MODE_IEEE80211B;
+ case HOSTAPD_MODE_IEEE80211G:
+ return QCA_ACS_MODE_IEEE80211G;
+ case HOSTAPD_MODE_IEEE80211A:
+ 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_ch_list(struct nl_msg *msg, const int *freq_list)
+{
+ int num_channels = 0, num_freqs;
+ u8 *ch_list;
+ enum hostapd_hw_mode hw_mode;
+ int ret = 0;
+ int i;
+
+ if (!freq_list)
+ return 0;
+
+ num_freqs = int_array_len(freq_list);
+ ch_list = os_malloc(sizeof(u8) * num_freqs);
+ if (!ch_list)
+ return -1;
+
+ for (i = 0; i < num_freqs; i++) {
+ const int freq = freq_list[i];
+
+ if (freq == 0)
+ break;
+ /* Send 2.4 GHz and 5 GHz channels with
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
+ * compatibility.
+ */
+ if (!(freq >= 2412 && freq <= 2484) &&
+ !(freq >= 5180 && freq <= 5900) &&
+ !(freq >= 5945 && freq <= 7115))
+ continue;
+ hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
+ if (hw_mode != NUM_HOSTAPD_MODES)
+ num_channels++;
+ }
+
+ if (num_channels)
+ ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+ num_channels, ch_list);
+
+ os_free(ch_list);
+ return ret;
+}
+
+
+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 nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv,
+ struct drv_acs_params *params)
+{
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int ret;
+ int mode;
+
+ mode = hw_mode_to_qca_acs(params->hw_mode);
+ if (mode < 0)
+ 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_DO_ACS) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
+ (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)) ||
+ (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) ||
+ add_acs_ch_list(msg, params->freq_list) ||
+ add_acs_freq_list(msg, params->freq_list) ||
+ (params->edmg_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width, params->edmg_enabled);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to invoke driver ACS function: %s",
+ strerror(-ret));
+ }
+ return ret;
+}
+
+
+static int nl80211_set_band(void *priv, u32 band_mask)
+{
+ 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_value;
+ u32 qca_band_mask = QCA_SETBAND_AUTO;
+
+ if (!drv->setband_vendor_cmd_avail ||
+ (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
+ return -1;
+
+ if (band_mask & WPA_SETBAND_5G)
+ qca_band_mask |= QCA_SETBAND_5G;
+ if (band_mask & WPA_SETBAND_2G)
+ qca_band_mask |= QCA_SETBAND_2G;
+ if (band_mask & WPA_SETBAND_6G)
+ qca_band_mask |= QCA_SETBAND_6G;
+
+ /*
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
+ * it suite to its values (AUTO/5G/2G) for backwards compatibility.
+ */
+ qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
+ (qca_band_mask & QCA_SETBAND_2G)) ?
+ QCA_SETBAND_AUTO :
+ qca_band_mask & ~QCA_SETBAND_6G;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
+ qca_band_mask, qca_band_value);
+
+ 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_value) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
+ qca_band_mask)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver setband function failed: %s",
+ strerror(-ret));
+ }
+ 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,
+ NULL, NULL);
+ 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, 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;
+}
+
+
+static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count, const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
+ freq, period, interval, count);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ 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_P2P_LISTEN_OFFLOAD_START))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ freq) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ period) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ interval) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ count) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ dev_types_len, device_types) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ ies_len, ies))
+ goto fail;
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to send P2P Listen offload vendor command");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_p2p_lo_stop(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ 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_P2P_LISTEN_OFFLOAD_STOP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+}
+
+
+static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+ u32 tdls_mode;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set TDKS mode: tdls_external_control=%d",
+ tdls_external_control);
+
+ if (tdls_external_control == 1)
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
+ else
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
+
+ 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_CONFIGURE_TDLS))
+ goto fail;
+
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!params)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
+ tdls_mode))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set TDLS mode failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+#ifdef CONFIG_MBO
+
+static enum mbo_transition_reject_reason
+nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
+{
+ switch (status) {
+ case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
+ return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
+ case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
+ return MBO_TRANSITION_REJECT_REASON_DELAY;
+ case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
+ return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
+ case QCA_STATUS_REJECT_LOW_RSSI:
+ return MBO_TRANSITION_REJECT_REASON_RSSI;
+ case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
+ return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
+ case QCA_STATUS_REJECT_UNKNOWN:
+ default:
+ return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
+ }
+}
+
+
+static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
+ struct nlattr *tb[], int num)
+{
+ enum qca_wlan_btm_candidate_status status;
+ char buf[50];
+
+ os_memcpy(candidate->bssid,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
+ ETH_ALEN);
+
+ status = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
+ candidate->is_accept = status == QCA_STATUS_ACCEPT;
+ candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
+
+ if (candidate->is_accept)
+ os_snprintf(buf, sizeof(buf), "Accepted");
+ else
+ os_snprintf(buf, sizeof(buf),
+ "Rejected, Reject_reason: %d",
+ candidate->reject_reason);
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
+ num, MAC2STR(candidate->bssid), buf);
+}
+
+
+static int
+nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
+{
+ struct wpa_bss_candidate_info *info = arg;
+ struct candidate_list *candidate = info->candidates;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
+ static struct nla_policy policy[
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
+ .minlen = ETH_ALEN
+ },
+ [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
+ .type = NLA_U32,
+ },
+ };
+ struct nlattr *attr;
+ int rem;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u8 num;
+
+ num = info->num; /* number of candidates sent to driver */
+ info->num = 0;
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
+ nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
+ !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
+ return NL_SKIP;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: WNM Candidate list received from driver");
+ nla_for_each_nested(attr,
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
+ rem) {
+ if (info->num >= num ||
+ nla_parse_nested(
+ tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
+ attr, policy) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
+ break;
+
+ nl80211_parse_btm_candidate_info(candidate, tb, info->num);
+
+ candidate++;
+ info->num++;
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct wpa_bss_candidate_info *
+nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *attr, *attr1, *attr2;
+ struct wpa_bss_candidate_info *info;
+ u8 i;
+ int ret;
+ u8 *pos;
+
+ if (!drv->fetch_bss_trans_status)
+ return NULL;
+
+ info = os_zalloc(sizeof(*info));
+ if (!info)
+ return NULL;
+ /* Allocate memory for number of candidates sent to driver */
+ info->candidates = os_calloc(params->n_candidates,
+ sizeof(*info->candidates));
+ if (!info->candidates) {
+ os_free(info);
+ return NULL;
+ }
+
+ /* Copy the number of candidates being sent to driver. This is used in
+ * nl80211_get_bss_transition_status_handler() to limit the number of
+ * candidates that can be populated in info->candidates and will be
+ * later overwritten with the actual number of candidates received from
+ * the driver.
+ */
+ info->num = params->n_candidates;
+
+ 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_FETCH_BSS_TRANSITION_STATUS))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
+ params->mbo_transition_reason))
+ goto fail;
+
+ attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
+ if (!attr1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
+ params->mbo_transition_reason, params->n_candidates);
+ pos = params->bssid;
+ for (i = 0; i < params->n_candidates; i++) {
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
+ MAC2STR(pos));
+ attr2 = nla_nest_start(msg, i);
+ if (!attr2 ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
+ ETH_ALEN, pos))
+ goto fail;
+ pos += ETH_ALEN;
+ nla_nest_end(msg, attr2);
+ }
+
+ nla_nest_end(msg, attr1);
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg,
+ nl80211_get_bss_transition_status_handler,
+ info, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ return info;
+
+fail:
+ nlmsg_free(msg);
+ os_free(info->candidates);
+ os_free(info);
+ return NULL;
+}
+
+
+/**
+ * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
+ * Returns: 0 on success, -1 on failure
+ */
+static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *attr;
+ int ret = -1;
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ 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_SET_WIFI_CONFIGURATION))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
+ ignore_disallow);
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
+ ignore_disallow))
+ goto fail;
+
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+#endif /* CONFIG_MBO */
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
+ struct drv_acs_params *params)
+{
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int freq_list_len;
+ int ret = -1;
+
+ freq_list_len = int_array_len(params->freq_list);
+ wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
+ __func__, freq_list_len);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ BRCM_VENDOR_SCMD_ACS) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
+ nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
+ params->ht_enabled) ||
+ nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
+ params->ht40_enabled) ||
+ nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
+ params->vht_enabled) ||
+ nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
+ (freq_list_len > 0 &&
+ nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+ sizeof(int) * freq_list_len, params->freq_list)))
+ goto fail;
+ nla_nest_end(msg, data);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: BRCM Failed to invoke driver ACS function: %s",
+ strerror(errno));
+ }
+
+ msg = NULL;
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
+
+static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
+{
+#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM)
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM */
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->qca_do_acs)
+ return nl80211_qca_do_acs(drv, params);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (drv->brcm_do_acs)
+ return wpa_driver_do_broadcom_acs(drv, params);
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
+ return -1;
+}
+
+
+static int nl80211_write_to_file(const char *name, unsigned int val)
+{
+ int fd, len;
+ char tmp[128];
+ int ret = 0;
+
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ int level;
+ /*
+ * Flags may not exist on older kernels, or while we're tearing
+ * down a disappearing device.
+ */
+ if (errno == ENOENT) {
+ ret = 0;
+ level = MSG_DEBUG;
+ } else {
+ ret = -1;
+ level = MSG_ERROR;
+ }
+ wpa_printf(level, "nl80211: Failed to open %s: %s",
+ name, strerror(errno));
+ return ret;
+ }
+
+ len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
+ len = write(fd, tmp, len);
+ if (len < 0) {
+ ret = -1;
+ wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
+ name, strerror(errno));
+ }
+ close(fd);
+
+ return ret;
+}
+
+
+static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ int ret;
+
+ /* P2P-Device has no netdev that can (or should) be configured here */
+ if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
+ filter_flags);
+
+ /* Configure filtering of unicast frame encrypted using GTK */
+ ret = os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
+ bss->ifname);
+ if (os_snprintf_error(sizeof(path), ret))
+ return -1;
+
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_GTK));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set IPv4 unicast in multicast filter");
+ return ret;
+ }
+
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_GTK));
+
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set IPv6 unicast in multicast filter");
+ return ret;
+ }
+
+ /* Configure filtering of unicast frame encrypted using GTK */
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_ARP));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed set gratuitous ARP filter");
+ return ret;
+ }
+
+ /* Configure filtering of IPv6 NA frames */
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_NA));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set unsolicited NA filter");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
+ const u8 **ext_capa, const u8 **ext_capa_mask,
+ unsigned int *ext_capa_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ enum nl80211_iftype nlmode;
+ unsigned int i;
+
+ if (!ext_capa || !ext_capa_mask || !ext_capa_len)
+ return -1;
+
+ nlmode = wpa_driver_nl80211_if_type(type);
+
+ /* By default, use the per-radio values */
+ *ext_capa = drv->extended_capa;
+ *ext_capa_mask = drv->extended_capa_mask;
+ *ext_capa_len = drv->extended_capa_len;
+
+ /* Replace the default value if a per-interface type value exists */
+ for (i = 0; i < drv->num_iface_ext_capa; i++) {
+ if (nlmode == drv->iface_ext_capa[i].iftype) {
+ *ext_capa = drv->iface_ext_capa[i].ext_capa;
+ *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
+ *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int nl80211_update_connection_params(
+ void *priv, struct wpa_driver_associate_params *params,
+ enum wpa_drv_update_connect_params_mask mask)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -1;
+ enum nl80211_auth_type type;
+
+ /* Update Connection Params is intended for drivers that implement
+ * internal SME and expect these updated connection params from
+ * wpa_supplicant. Do not send this request for the drivers using
+ * SME from wpa_supplicant.
+ */
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ return 0;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
+ if (!msg)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
+ drv->ifindex);
+
+ if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
+ if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie))
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
+ params->wpa_ie_len);
+ }
+
+ if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
+ type = get_nl_auth_type(params->auth_alg);
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ }
+
+ if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
+ nl80211_put_fils_connect_params(drv, params, msg))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret)
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: Update connect params command failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_send_external_auth_status(void *priv,
+ struct external_auth *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ int ret = -1;
+
+ /* External auth command/status is intended for drivers that implement
+ * internal SME but want to offload authentication processing (e.g.,
+ * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
+ * which do not support AP SME or use wpa_supplicant/hostapd SME.
+ */
+ if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return -1;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: External auth status: %u", params->status);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
+ (params->ssid && params->ssid_len &&
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+ (params->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
+ (params->bssid &&
+ nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
+ goto fail;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: External Auth status update failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
+ int val)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+ val ? "Enable" : "Disable", bridge_ifname);
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+ goto fail;
+
+ if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+ if (linux_br_del_if(drv->global->ioctl_sock,
+ bridge_ifname, bss->ifname)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to remove interface %s from bridge %s",
+ bss->ifname, bridge_ifname);
+ return -1;
+ }
+ bss->added_if_into_bridge = 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ msg = NULL;
+ if (ret && val && nl80211_get_4addr(bss) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: 4addr mode was already enabled");
+ ret = 0;
+ }
+ if (!ret) {
+ if (bridge_ifname[0] && val &&
+ i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
+ return -1;
+ return 0;
+ }
+
+fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
+
+ return ret;
+}
+
+
+#ifdef CONFIG_DPP
+static int nl80211_dpp_listen(void *priv, bool enable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
+ struct nl_sock *handle;
+
+ if (!drv->multicast_registrations || !bss->nl_mgmt)
+ return 0; /* cannot do more than hope broadcast RX works */
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
+ enable ? "enable" : "disable");
+ handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
+ return nl80211_register_frame(bss, handle, type,
+ (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
+ enable);
+}
+#endif /* CONFIG_DPP */
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int testing_nl80211_register_frame(void *priv, u16 type,
+ const u8 *match, size_t match_len,
+ bool multicast)
+{
+ struct i802_bss *bss = priv;
+ struct nl_sock *handle;
+
+ if (!bss->nl_mgmt)
+ return -1;
+ handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
+ return nl80211_register_frame(bss, handle, type, match, match_len,
+ multicast);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .desc = "Linux nl80211/cfg80211",
+ .get_bssid = wpa_driver_nl80211_get_bssid,
+ .get_ssid = wpa_driver_nl80211_get_ssid,
+ .set_key = driver_nl80211_set_key,
+ .scan2 = driver_nl80211_scan2,
+ .sched_scan = wpa_driver_nl80211_sched_scan,
+ .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
+ .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+ .abort_scan = wpa_driver_nl80211_abort_scan,
+ .deauthenticate = driver_nl80211_deauthenticate,
+ .authenticate = driver_nl80211_authenticate,
+ .associate = wpa_driver_nl80211_associate,
+ .global_init = nl80211_global_init,
+ .global_deinit = nl80211_global_deinit,
+ .init2 = wpa_driver_nl80211_init,
+ .deinit = driver_nl80211_deinit,
+ .get_capa = wpa_driver_nl80211_get_capa,
+ .set_operstate = wpa_driver_nl80211_set_operstate,
+ .set_supp_port = wpa_driver_nl80211_set_supp_port,
+ .set_country = wpa_driver_nl80211_set_country,
+ .get_country = wpa_driver_nl80211_get_country,
+ .set_ap = wpa_driver_nl80211_set_ap,
+ .set_acl = wpa_driver_nl80211_set_acl,
+ .if_add = wpa_driver_nl80211_if_add,
+ .if_remove = driver_nl80211_if_remove,
+ .send_mlme = driver_nl80211_send_mlme,
+ .get_hw_feature_data = nl80211_get_hw_feature_data,
+ .sta_add = wpa_driver_nl80211_sta_add,
+ .sta_remove = driver_nl80211_sta_remove,
+ .tx_control_port = nl80211_tx_control_port,
+ .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
+ .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
+ .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
+ .hapd_init = i802_init,
+ .hapd_deinit = i802_deinit,
+ .set_wds_sta = i802_set_wds_sta,
+ .get_seqnum = i802_get_seqnum,
+ .flush = i802_flush,
+ .get_inact_sec = i802_get_inact_sec,
+ .sta_clear_stats = i802_sta_clear_stats,
+ .set_rts = i802_set_rts,
+ .set_frag = i802_set_frag,
+ .set_tx_queue_params = i802_set_tx_queue_params,
+ .set_sta_vlan = driver_nl80211_set_sta_vlan,
+ .sta_deauth = i802_sta_deauth,
+ .sta_disassoc = i802_sta_disassoc,
+ .read_sta_data = driver_nl80211_read_sta_data,
+ .set_freq = i802_set_freq,
+ .send_action = driver_nl80211_send_action,
+ .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
+ .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
+ .cancel_remain_on_channel =
+ wpa_driver_nl80211_cancel_remain_on_channel,
+ .probe_req_report = driver_nl80211_probe_req_report,
+ .deinit_ap = wpa_driver_nl80211_deinit_ap,
+ .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
+ .resume = wpa_driver_nl80211_resume,
+ .signal_monitor = nl80211_signal_monitor,
+ .signal_poll = nl80211_signal_poll,
+ .channel_info = nl80211_channel_info,
+ .set_param = nl80211_set_param,
+ .get_radio_name = nl80211_get_radio_name,
+ .add_pmkid = nl80211_add_pmkid,
+ .remove_pmkid = nl80211_remove_pmkid,
+ .flush_pmkid = nl80211_flush_pmkid,
+ .set_rekey_info = nl80211_set_rekey_info,
+ .poll_client = nl80211_poll_client,
+ .set_p2p_powersave = nl80211_set_p2p_powersave,
+ .start_dfs_cac = nl80211_start_radar_detection,
+ .stop_ap = wpa_driver_nl80211_stop_ap,
+#ifdef CONFIG_TDLS
+ .send_tdls_mgmt = nl80211_send_tdls_mgmt,
+ .tdls_oper = nl80211_tdls_oper,
+ .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+ .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
+#endif /* CONFIG_TDLS */
+ .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+ .update_dh_ie = nl80211_update_dh_ie,
+ .get_mac_addr = wpa_driver_nl80211_get_macaddr,
+ .get_survey = wpa_driver_nl80211_get_survey,
+ .status = wpa_driver_nl80211_status,
+ .switch_channel = nl80211_switch_channel,
+#ifdef ANDROID_P2P
+ .set_noa = wpa_driver_set_p2p_noa,
+ .get_noa = wpa_driver_get_p2p_noa,
+ .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,
+ .get_wowlan = nl80211_get_wowlan,
+ .set_wowlan = nl80211_set_wowlan,
+ .set_mac_addr = nl80211_set_mac_addr,
+#ifdef CONFIG_MESH
+ .init_mesh = wpa_driver_nl80211_init_mesh,
+ .join_mesh = wpa_driver_nl80211_join_mesh,
+ .leave_mesh = wpa_driver_nl80211_leave_mesh,
+ .probe_mesh_link = nl80211_probe_mesh_link,
+#endif /* CONFIG_MESH */
+ .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
+ .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
+ .br_port_set_attr = wpa_driver_br_port_set_attr,
+ .br_set_net_param = wpa_driver_br_set_net_param,
+ .add_tx_ts = nl80211_add_ts,
+ .del_tx_ts = nl80211_del_ts,
+ .get_ifindex = nl80211_get_ifindex,
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ .roaming = nl80211_roaming,
+ .disable_fils = nl80211_disable_fils,
+ .set_band = nl80211_set_band,
+ .get_pref_freq_list = nl80211_get_pref_freq_list,
+ .set_prob_oper_freq = nl80211_set_prob_oper_freq,
+ .p2p_lo_start = nl80211_p2p_lo_start,
+ .p2p_lo_stop = nl80211_p2p_lo_stop,
+ .set_default_scan_ies = nl80211_set_default_scan_ies,
+ .set_tdls_mode = nl80211_set_tdls_mode,
+#ifdef CONFIG_MBO
+ .get_bss_transition_status = nl80211_get_bss_transition_status,
+ .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
+#endif /* CONFIG_MBO */
+ .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
+ .add_sta_node = nl80211_add_sta_node,
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ .do_acs = nl80211_do_acs,
+ .configure_data_frame_filters = nl80211_configure_data_frame_filters,
+ .get_ext_capab = nl80211_get_ext_capab,
+ .update_connect_params = nl80211_update_connection_params,
+ .send_external_auth_status = nl80211_send_external_auth_status,
+ .set_4addr_mode = nl80211_set_4addr_mode,
+#ifdef CONFIG_DPP
+ .dpp_listen = nl80211_dpp_listen,
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_TESTING_OPTIONS
+ .register_frame = testing_nl80211_register_frame,
+#endif /* CONFIG_TESTING_OPTIONS */
+};
diff --git a/contrib/wpa/src/drivers/driver_nl80211.h b/contrib/wpa/src/drivers/driver_nl80211.h
index 74982694561e..9d61c1d6930f 100644
--- a/contrib/wpa/src/drivers/driver_nl80211.h
+++ b/contrib/wpa/src/drivers/driver_nl80211.h
@@ -17,12 +17,10 @@
#include "utils/list.h"
#include "driver.h"
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#endif /* CONFIG_LIBNL20 */
+#ifndef NL_CAPABILITY_VERSION_3_5_0
+#define nla_nest_start(msg, attrtype) \
+ nla_nest_start(msg, NLA_F_NESTED | (attrtype))
+#endif
struct nl80211_global {
void *ctx;
@@ -32,11 +30,11 @@ struct nl80211_global {
int if_add_wdevid_set;
struct netlink_data *netlink;
struct nl_cb *nl_cb;
- struct nl_handle *nl;
+ struct nl_sock *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
- struct nl_handle *nl_event;
+ struct nl_sock *nl_event;
};
struct nl80211_wiphy_data {
@@ -44,7 +42,7 @@ struct nl80211_wiphy_data {
struct dl_list bsss;
struct dl_list drvs;
- struct nl_handle *nl_beacons;
+ struct nl_sock *nl_beacons;
struct nl_cb *nl_cb;
int wiphy_idx;
@@ -75,7 +73,7 @@ struct i802_bss {
int if_dynamic;
void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
+ struct nl_sock *nl_preq, *nl_mgmt, *nl_connect;
struct nl_cb *nl_cb;
struct nl80211_wiphy_data *wiphy_data;
@@ -113,6 +111,7 @@ struct wpa_driver_nl80211_data {
unsigned int num_iface_ext_capa;
int has_capability;
+ int has_driver_key_mgmt;
int operstate;
@@ -150,7 +149,7 @@ struct wpa_driver_nl80211_data {
unsigned int ignore_next_local_disconnect:1;
unsigned int ignore_next_local_deauth:1;
unsigned int hostapd:1;
- unsigned int start_mode_ap:1;
+ unsigned int start_mode_sta:1;
unsigned int start_iface_up:1;
unsigned int test_use_roc_tx:1;
unsigned int ignore_deauth_event:1;
@@ -171,14 +170,23 @@ struct wpa_driver_nl80211_data {
unsigned int set_wifi_conf_vendor_cmd_avail:1;
unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
- unsigned int get_supported_akm_suites_avail:1;
+ unsigned int add_sta_node_vendor_cmd_avail:1;
+ unsigned int control_port_ap:1;
+ unsigned int multicast_registrations:1;
+ unsigned int no_rrm:1;
+ unsigned int get_sta_info_vendor_cmd_avail:1;
+ unsigned int fils_discovery:1;
+ unsigned int unsol_bcast_probe_resp:1;
+ unsigned int qca_do_acs:1;
+ unsigned int brcm_do_acs:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
- u64 send_action_cookie;
-#define MAX_SEND_ACTION_COOKIES 20
- u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
- unsigned int num_send_action_cookies;
+ u64 send_frame_cookie;
+#define MAX_SEND_FRAME_COOKIES 20
+ u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
+ unsigned int num_send_frame_cookies;
+ u64 eapol_tx_cookie;
unsigned int last_mgmt_freq;
@@ -191,7 +199,7 @@ struct wpa_driver_nl80211_data {
int eapol_sock; /* socket for EAPOL frames */
- struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+ struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
struct drv_nl80211_if_info default_if_indices[16];
struct drv_nl80211_if_info *if_indices;
@@ -205,6 +213,8 @@ struct wpa_driver_nl80211_data {
int auth_alg;
u8 *auth_ie;
size_t auth_ie_len;
+ u8 *auth_data;
+ size_t auth_data_len;
u8 auth_wep_key[4][16];
size_t auth_wep_key_len[4];
int auth_wep_tx_keyidx;
@@ -217,6 +227,12 @@ struct wpa_driver_nl80211_data {
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ bool roam_indication_done;
+ u8 *pending_roam_data;
+ size_t pending_roam_data_len;
+ struct os_reltime pending_roam_ind_time;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
};
struct nl_msg;
@@ -229,7 +245,10 @@ struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data);
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data);
+struct nl_sock * get_connect_handle(struct i802_bss *bss);
int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
const u8 *addr, int wds,
@@ -255,7 +274,7 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change,
- struct nl_handle *nl_connect);
+ struct i802_bss *bss);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -273,13 +292,19 @@ int process_bss_event(struct nl_msg *msg, void *arg);
const char * nl80211_iftype_str(enum nl80211_iftype mode);
+void nl80211_restore_ap_mode(struct i802_bss *bss);
+
#ifdef ANDROID
-int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_nl_socket_set_nonblocking(struct nl_sock *handle);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len);
+extern int wpa_driver_nl80211_driver_event(struct wpa_driver_nl80211_data *drv,
+ u32 vendor_id, u32 subcmd,
+ u8 *data, size_t len);
+
#ifdef ANDROID_P2P
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
diff --git a/contrib/wpa/src/drivers/driver_nl80211_android.c b/contrib/wpa/src/drivers/driver_nl80211_android.c
index ba47888843bb..9431a12d4dc0 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_android.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_android.c
@@ -182,9 +182,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
#endif /* ANDROID_P2P */
-int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+int android_nl_socket_set_nonblocking(struct nl_sock *handle)
{
return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
}
-
-
diff --git a/contrib/wpa/src/drivers/driver_nl80211_capa.c b/contrib/wpa/src/drivers/driver_nl80211_capa.c
index 8318b10ab9e7..cd596e311e59 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_capa.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_capa.c
@@ -16,6 +16,7 @@
#include "common/wpa_common.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
+#include "common/brcm_vendor.h"
#include "driver_nl80211.h"
@@ -49,7 +50,8 @@ static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
return 0;
}
- if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat,
+ NULL, NULL) == 0)
return feat;
return 0;
@@ -78,6 +80,9 @@ struct wiphy_info_data {
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
unsigned int mac_addr_rand_sched_scan_supported:1;
+ unsigned int update_ft_ies_supported:1;
+ unsigned int has_key_mgmt:1;
+ unsigned int has_key_mgmt_iftype:1;
};
@@ -243,11 +248,187 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
case NL80211_CMD_SET_QOS_MAP:
info->set_qos_map_supported = 1;
break;
+ case NL80211_CMD_UPDATE_FT_IES:
+ info->update_ft_ies_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static unsigned int get_akm_suites_info(struct nlattr *tb)
+{
+ int i, num;
+ unsigned int key_mgmt = 0;
+ u32 *akms;
+
+ if (!tb)
+ return 0;
+
+ num = nla_len(tb) / sizeof(u32);
+ akms = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ switch (akms[i]) {
+ case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_PSK:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_CCKM:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_CCKM;
+ break;
+ case RSN_AUTH_KEY_MGMT_OSEN:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OSEN;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ break;
+ case RSN_AUTH_KEY_MGMT_OWE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE;
+ break;
+ case RSN_AUTH_KEY_MGMT_DPP:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ break;
+ }
+ }
+
+ return key_mgmt;
+}
+
+
+static void get_iface_akm_suites_info(struct wiphy_info_data *info,
+ struct nlattr *nl_akms)
+{
+ struct nlattr *tb[NL80211_IFTYPE_AKM_ATTR_MAX + 1];
+ struct nlattr *nl_iftype;
+ unsigned int key_mgmt;
+ int i;
+
+ if (!nl_akms)
+ return;
+
+ nla_parse(tb, NL80211_IFTYPE_AKM_ATTR_MAX,
+ nla_data(nl_akms), nla_len(nl_akms), NULL);
+
+ if (!tb[NL80211_IFTYPE_AKM_ATTR_IFTYPES] ||
+ !tb[NL80211_IFTYPE_AKM_ATTR_SUITES])
+ return;
+
+ info->has_key_mgmt_iftype = 1;
+ key_mgmt = get_akm_suites_info(tb[NL80211_IFTYPE_AKM_ATTR_SUITES]);
+
+ nla_for_each_nested(nl_iftype, tb[NL80211_IFTYPE_AKM_ATTR_IFTYPES], i) {
+ switch (nla_type(nl_iftype)) {
+ case NL80211_IFTYPE_ADHOC:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_IBSS] = key_mgmt;
+ break;
+ case NL80211_IFTYPE_STATION:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_STATION] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_AP:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_AP_BSS] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_AP_VLAN] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_MESH] = key_mgmt;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_CLIENT] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_GO] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_P2P_DEVICE] =
+ key_mgmt;
+ break;
+ case NL80211_IFTYPE_NAN:
+ info->drv->capa.key_mgmt_iftype[WPA_IF_NAN] = key_mgmt;
+ break;
}
+ wpa_printf(MSG_DEBUG, "nl80211: %s supported key_mgmt 0x%x",
+ nl80211_iftype_str(nla_type(nl_iftype)),
+ key_mgmt);
}
}
+static void wiphy_info_iftype_akm_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_if;
+ int rem_if;
+
+ if (!tb)
+ return;
+
+ nla_for_each_nested(nl_if, tb, rem_if)
+ get_iface_akm_suites_info(info, nl_if);
+}
+
+
+static void wiphy_info_akm_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ if (!tb)
+ return;
+
+ info->has_key_mgmt = 1;
+ info->capa->key_mgmt = get_akm_suites_info(tb);
+ wpa_printf(MSG_DEBUG, "nl80211: wiphy supported key_mgmt 0x%x",
+ info->capa->key_mgmt);
+}
+
+
static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
struct nlattr *tb)
{
@@ -379,6 +560,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_RATE_HE;
+
+ if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SET_SCAN_DWELL))
capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
@@ -433,6 +618,53 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
+ capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ if (ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_VLAN_OFFLOAD;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0))
+ capa->flags |= WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_PROTECTION;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_EXT_KEY_ID))
+ capa->flags |= WPA_DRIVER_FLAGS_EXTENDED_KEY_ID;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS))
+ info->drv->multicast_registrations = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY))
+ info->drv->fils_discovery = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
+ info->drv->unsol_bcast_probe_resp = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
}
@@ -479,12 +711,6 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
info->mac_addr_rand_sched_scan_supported = 1;
- if (flags & NL80211_FEATURE_STATIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
-
- if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
-
if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
info->wmm_ac_supported = 1;
@@ -665,12 +891,14 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
if (tb[NL80211_ATTR_MAC_ACL_MAX])
capa->max_acl_mac_addrs =
- nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+ nla_get_u32(tb[NL80211_ATTR_MAC_ACL_MAX]);
wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
+ wiphy_info_akm_suites(info, tb[NL80211_ATTR_AKM_SUITES]);
+ wiphy_info_iftype_akm_suites(info, tb[NL80211_ATTR_IFTYPE_AKM_SUITES]);
if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -768,6 +996,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
drv->capa.flags |=
WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ drv->qca_do_acs = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
drv->setband_vendor_cmd_avail = 1;
@@ -784,11 +1013,26 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_ROAM:
drv->roam_vendor_cmd_avail = 1;
break;
- case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
- drv->get_supported_akm_suites_avail = 1;
+ case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
+ drv->add_sta_node_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO:
+ drv->get_sta_info_vendor_cmd_avail = 1;
break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ } else if (vinfo->vendor_id == OUI_BRCM) {
+ switch (vinfo->subcmd) {
+ case BRCM_VENDOR_SCMD_ACS:
+ drv->capa.flags |=
+ WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ wpa_printf(MSG_DEBUG,
+ "Enabled BRCM ACS");
+ drv->brcm_do_acs = 1;
+ break;
+ }
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
@@ -850,7 +1094,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
return -1;
}
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info, NULL, NULL))
return -1;
if (info->auth_supported)
@@ -901,6 +1145,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
drv->capa.max_sched_scan_plan_iterations = 0;
}
+ if (info->update_ft_ies_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
+
return 0;
}
@@ -953,132 +1200,13 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
return;
}
- ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability,
+ NULL, NULL);
if (!ret && dfs_capability)
drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
}
-static unsigned int get_akm_suites_info(struct nlattr *tb)
-{
- int i, num;
- unsigned int key_mgmt = 0;
- u32 *akms;
-
- if (!tb)
- return 0;
-
- num = nla_len(tb) / sizeof(u32);
- akms = nla_data(tb);
- for (i = 0; i < num; i++) {
- u32 a = akms[i];
-
- wpa_printf(MSG_DEBUG,
- "nl80211: Supported AKM %02x-%02x-%02x:%u",
- a >> 24, (a >> 16) & 0xff,
- (a >> 8) & 0xff, a & 0xff);
- switch (a) {
- case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
- break;
- case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- break;
- case RSN_AUTH_KEY_MGMT_FT_802_1X:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT;
- break;
- case RSN_AUTH_KEY_MGMT_FT_PSK:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
- break;
- case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
- break;
- case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
- break;
- case RSN_AUTH_KEY_MGMT_OWE:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE;
- break;
- case RSN_AUTH_KEY_MGMT_DPP:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP;
- break;
- case RSN_AUTH_KEY_MGMT_FILS_SHA256:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256;
- break;
- case RSN_AUTH_KEY_MGMT_FILS_SHA384:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
- break;
- case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256;
- break;
- case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
- break;
- case RSN_AUTH_KEY_MGMT_SAE:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
- break;
- }
- }
-
- return key_mgmt;
-}
-
-
-static int get_akm_suites_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- unsigned int *key_mgmt = arg;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
- struct nlattr *tb_data[NL80211_ATTR_MAX + 1];
-
- nla_parse(tb_data, NL80211_ATTR_MAX,
- nla_data(nl_vend), nla_len(nl_vend), NULL);
-
- *key_mgmt =
- get_akm_suites_info(tb_data[NL80211_ATTR_AKM_SUITES]);
- }
-
- return NL_SKIP;
-}
-
-
-static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv)
-{
- struct nl_msg *msg;
- unsigned int key_mgmt = 0;
- int ret;
-
- if (!drv->get_supported_akm_suites_avail)
- 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_GET_SUPPORTED_AKMS)) {
- nlmsg_free(msg);
- return -1;
- }
-
- ret = send_and_recv_msgs(drv, msg, get_akm_suites_handler, &key_mgmt);
- if (!ret) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x",
- key_mgmt);
- drv->capa.key_mgmt = key_mgmt;
- }
-
- return ret;
-}
-
-
struct features_info {
u8 *flags;
size_t flags_len;
@@ -1160,7 +1288,8 @@ 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);
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info,
+ NULL, NULL);
if (ret || !info.flags)
return;
@@ -1190,6 +1319,8 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
{
struct wiphy_info_data info;
+ int i;
+
if (wpa_driver_nl80211_get_info(drv, &info))
return -1;
@@ -1197,30 +1328,62 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
return -1;
drv->has_capability = 1;
- drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 |
- WPA_DRIVER_CAPA_KEY_MGMT_OWE |
- WPA_DRIVER_CAPA_KEY_MGMT_DPP;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
- drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
- WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
- WPA_DRIVER_CAPA_KEY_MGMT_SAE;
- else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
- drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
- WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
-
-#ifdef CONFIG_DRIVER_NL80211_QCA
- /* Override drv->capa.key_mgmt based on driver advertised capability
- * constraints, if available. */
- qca_nl80211_get_akm_suites(drv);
-#endif /* CONFIG_DRIVER_NL80211_QCA */
+ drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype;
+
+ /* Fallback to hardcoded defaults if the driver does nott advertize any
+ * AKM capabilities. */
+ if (!drv->has_driver_key_mgmt) {
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
+ WPA_DRIVER_CAPA_KEY_MGMT_OWE |
+ WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+
+ if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 |
+ WPA_DRIVER_CAPA_ENC_GCMP_256))
+ drv->capa.key_mgmt |=
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ drv->capa.key_mgmt |=
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
+ drv->capa.key_mgmt |=
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+ }
+
+ if (!info.has_key_mgmt_iftype) {
+ /* If the driver does not advertize per interface AKM
+ * capabilities, consider all interfaces to support default AKMs
+ * in key_mgmt. */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
+ } else if (info.has_key_mgmt_iftype && !info.has_key_mgmt) {
+ /* If the driver advertizes only per interface supported AKMs
+ * but does not advertize per wiphy AKM capabilities, consider
+ * the default key_mgmt as a mask of per interface supported
+ * AKMs. */
+ drv->capa.key_mgmt = 0;
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt |= drv->capa.key_mgmt_iftype[i];
+ } else if (info.has_key_mgmt_iftype && info.has_key_mgmt) {
+ /* If the driver advertizes AKM capabilities both per wiphy and
+ * per interface, consider the interfaces for which per
+ * interface AKM capabilities were not received to support the
+ * default key_mgmt capabilities.
+ */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ if (!drv->capa.key_mgmt_iftype[i])
+ drv->capa.key_mgmt_iftype[i] =
+ drv->capa.key_mgmt;
+ }
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
@@ -1241,6 +1404,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_AP_SME;
/*
* No AP SME is currently assumed to also indicate no AP MLME
@@ -1288,6 +1452,12 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth,
+ (unsigned long long) drv->capa.flags, drv->capa.rrm_flags,
+ drv->capa.probe_resp_offloads, drv->capa.max_stations,
+ drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids);
return 0;
}
@@ -1337,17 +1507,54 @@ static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
}
+static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *bw_config,
+ struct nlattr *channels)
+{
+ if (!bw_config || !channels)
+ return NL_OK;
+
+ mode->edmg.bw_config = nla_get_u8(bw_config);
+ mode->edmg.channels = nla_get_u8(channels);
+
+ if (!mode->edmg.channels || !mode->edmg.bw_config)
+ return NL_STOP;
+
+ return NL_OK;
+}
+
+
+static int cw2ecw(unsigned int cw)
+{
+ int bit;
+
+ if (cw == 0)
+ return 0;
+
+ for (bit = 1; cw != 1; bit++)
+ cw >>= 1;
+
+ return bit;
+}
+
+
static void phy_info_freq(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *chan,
struct nlattr *tb_freq[])
{
u8 channel;
+
+ os_memset(chan, 0, sizeof(*chan));
chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
chan->flag = 0;
chan->allowed_bw = ~0;
chan->dfs_cac_ms = 0;
if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
chan->chan = channel;
+ else
+ wpa_printf(MSG_DEBUG,
+ "nl80211: No channel number found for frequency %u MHz",
+ chan->freq);
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
chan->flag |= HOSTAPD_CHAN_DISABLED;
@@ -1403,6 +1610,12 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
[NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
[NL80211_WMMR_TXOP] = { .type = NLA_U16 },
};
+ static const u8 wmm_map[4] = {
+ [NL80211_AC_BE] = WMM_AC_BE,
+ [NL80211_AC_BK] = WMM_AC_BK,
+ [NL80211_AC_VI] = WMM_AC_VI,
+ [NL80211_AC_VO] = WMM_AC_VO,
+ };
struct nlattr *nl_wmm;
struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
int rem_wmm, ac, count = 0;
@@ -1424,16 +1637,19 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
return;
}
ac = nl_wmm->nla_type;
- if (ac < 0 || ac >= WMM_AC_NUM) {
+ if ((unsigned int) ac >= ARRAY_SIZE(wmm_map)) {
wpa_printf(MSG_DEBUG,
"nl80211: Invalid AC value %d", ac);
return;
}
+ ac = wmm_map[ac];
chan->wmm_rules[ac].min_cwmin =
- nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MIN]));
chan->wmm_rules[ac].min_cwmax =
- nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]);
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MAX]));
chan->wmm_rules[ac].min_aifs =
nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
chan->wmm_rules[ac].max_txop =
@@ -1619,6 +1835,13 @@ static void phy_info_iftype_copy(struct he_capabilities *he_capab,
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
len);
}
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]) {
+ u16 capa;
+
+ capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
+ he_capab->he_6ghz_capa = le_to_host16(capa);
+ }
}
@@ -1694,7 +1917,12 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ ret = phy_info_edmg_capa(mode,
+ tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
+ tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
+ if (ret == NL_OK)
+ ret = phy_info_freqs(phy_info, mode,
+ tb_band[NL80211_BAND_ATTR_FREQS]);
if (ret == NL_OK)
ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
if (ret != NL_OK) {
@@ -1756,7 +1984,10 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
for (m = 0; m < *num_modes; m++) {
if (!modes[m].num_channels)
continue;
- if (modes[m].channels[0].freq < 4000) {
+ if (modes[m].channels[0].freq < 2000) {
+ modes[m].num_channels = 0;
+ continue;
+ } else if (modes[m].channels[0].freq < 4000) {
modes[m].mode = HOSTAPD_MODE_IEEE80211B;
for (i = 0; i < modes[m].num_rates; i++) {
if (modes[m].rates[i] > 200) {
@@ -1770,6 +2001,24 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
modes[m].mode = HOSTAPD_MODE_IEEE80211A;
}
+ /* Remove unsupported bands */
+ m = 0;
+ while (m < *num_modes) {
+ if (modes[m].mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove unsupported mode");
+ os_free(modes[m].channels);
+ os_free(modes[m].rates);
+ if (m + 1 < *num_modes)
+ os_memmove(&modes[m], &modes[m + 1],
+ sizeof(struct hostapd_hw_modes) *
+ (*num_modes - (m + 1)));
+ (*num_modes)--;
+ continue;
+ }
+ m++;
+ }
+
/* If only 802.11g mode is included, use it to construct matching
* 802.11b mode data. */
@@ -2144,7 +2393,8 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
}
}
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results,
+ NULL, NULL);
}
@@ -2233,7 +2483,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
return NULL;
}
- if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result,
+ NULL, NULL) == 0) {
struct hostapd_hw_modes *modes;
nl80211_set_regulatory_flags(drv, &result);
diff --git a/contrib/wpa/src/drivers/driver_nl80211_event.c b/contrib/wpa/src/drivers/driver_nl80211_event.c
index 7c16330662eb..0f0a01d0180b 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_event.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_event.c
@@ -15,11 +15,18 @@
#include "utils/eloop.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
+#include "common/brcm_vendor.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "driver_nl80211.h"
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie);
+
+
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
#define C2S(x) case x: return #x;
@@ -131,16 +138,45 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_SET_QOS_MAP)
C2S(NL80211_CMD_ADD_TX_TS)
C2S(NL80211_CMD_DEL_TX_TS)
+ C2S(NL80211_CMD_GET_MPP)
+ C2S(NL80211_CMD_JOIN_OCB)
+ C2S(NL80211_CMD_LEAVE_OCB)
+ C2S(NL80211_CMD_CH_SWITCH_STARTED_NOTIFY)
+ C2S(NL80211_CMD_TDLS_CHANNEL_SWITCH)
+ C2S(NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH)
C2S(NL80211_CMD_WIPHY_REG_CHANGE)
+ C2S(NL80211_CMD_ABORT_SCAN)
+ C2S(NL80211_CMD_START_NAN)
+ C2S(NL80211_CMD_STOP_NAN)
+ C2S(NL80211_CMD_ADD_NAN_FUNCTION)
+ C2S(NL80211_CMD_DEL_NAN_FUNCTION)
+ C2S(NL80211_CMD_CHANGE_NAN_CONFIG)
+ C2S(NL80211_CMD_NAN_MATCH)
+ C2S(NL80211_CMD_SET_MULTICAST_TO_UNICAST)
+ C2S(NL80211_CMD_UPDATE_CONNECT_PARAMS)
+ C2S(NL80211_CMD_SET_PMK)
+ C2S(NL80211_CMD_DEL_PMK)
C2S(NL80211_CMD_PORT_AUTHORIZED)
+ C2S(NL80211_CMD_RELOAD_REGDB)
C2S(NL80211_CMD_EXTERNAL_AUTH)
C2S(NL80211_CMD_STA_OPMODE_CHANGED)
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
+ C2S(NL80211_CMD_GET_FTM_RESPONDER_STATS)
+ C2S(NL80211_CMD_PEER_MEASUREMENT_START)
+ C2S(NL80211_CMD_PEER_MEASUREMENT_RESULT)
+ C2S(NL80211_CMD_PEER_MEASUREMENT_COMPLETE)
+ C2S(NL80211_CMD_NOTIFY_RADAR)
C2S(NL80211_CMD_UPDATE_OWE_INFO)
- default:
- return "NL80211_CMD_UNKNOWN";
+ C2S(NL80211_CMD_PROBE_MESH_LINK)
+ C2S(NL80211_CMD_SET_TID_CONFIG)
+ C2S(NL80211_CMD_UNPROT_BEACON)
+ C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_SAR_SPECS)
+ C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
+
+ return "NL80211_CMD_UNKNOWN";
}
@@ -287,6 +323,94 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
+static int qca_drv_connect_fail_reason_code_handler(struct nl_msg *msg,
+ void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u32 *reason_code = arg;
+
+ *reason_code = 0;
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+ wpa_printf(MSG_ERROR, "%s: Vendor data not found", __func__);
+ return NL_SKIP;
+ }
+
+ nla_parse(tb_sta_info, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX,
+ nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+ nla_len(tb[NL80211_ATTR_VENDOR_DATA]), NULL);
+
+ if (!tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]) {
+ wpa_printf(MSG_INFO, "%s: Vendor attr not found", __func__);
+ return NL_SKIP;
+ }
+
+ *reason_code = nla_get_u32(tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]);
+
+ return NL_SKIP;
+}
+
+
+static enum qca_sta_connect_fail_reason_codes
+drv_get_connect_fail_reason_code(struct wpa_driver_nl80211_data *drv)
+{
+ enum qca_sta_connect_fail_reason_codes reason_code;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg || nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO)) {
+ nlmsg_free(msg);
+ return 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg,
+ qca_drv_connect_fail_reason_code_handler,
+ &reason_code, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Get connect fail reason_code failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+ return reason_code;
+}
+
+
+static enum sta_connect_fail_reason_codes
+convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes
+ reason_code)
+{
+ switch (reason_code) {
+ case QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND:
+ return STA_CONNECT_FAIL_REASON_NO_BSS_FOUND;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL:
+ return STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL:
+ return STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED;
+ case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED:
+ return STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED;
+ default:
+ return STA_CONNECT_FAIL_REASON_UNSPECIFIED;
+ }
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie,
@@ -376,6 +500,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
if (fils_erp_next_seq_num)
event.assoc_reject.fils_erp_next_seq_num =
nla_get_u16(fils_erp_next_seq_num);
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->get_sta_info_vendor_cmd_avail) {
+ enum qca_sta_connect_fail_reason_codes reason_code;
+
+ reason_code = drv_get_connect_fail_reason_code(drv);
+ event.assoc_reject.reason_code =
+ convert_connect_fail_reason_codes(reason_code);
+ }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return;
}
@@ -463,6 +598,13 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
event.assoc_info.fils_pmkid = nla_data(fils_pmkid);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+
+ /* Avoid a race condition by stopping to ignore any following
+ * disconnection events now that the driver has indicated it is
+ * connected since that connection could have been triggered by a roam
+ * operation that happened in parallel with the disconnection request.
+ */
+ drv->ignore_next_local_disconnect = 0;
}
@@ -522,8 +664,14 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
case CHAN_WIDTH_160:
freq1 = cf1 - 70;
break;
- case CHAN_WIDTH_UNKNOWN:
case CHAN_WIDTH_80P80:
+ freq1 = cf1 - 30;
+ break;
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_2160:
+ case CHAN_WIDTH_4320:
+ case CHAN_WIDTH_6480:
+ case CHAN_WIDTH_8640:
/* FIXME: implement this */
return 0;
}
@@ -581,6 +729,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
nla_get_u32(freq),
nla_get_u32(cf1),
cf2 ? nla_get_u32(cf2) : 0);
+ wpa_printf(MSG_DEBUG, "nl80211: Calculated channel offset: %d",
+ chan_offset);
} else {
wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
}
@@ -679,29 +829,52 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
size_t len, struct nlattr *ack)
{
union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
+ u16 fc = le_to_host16(hdr->frame_control);
+ u64 cookie_val = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
+ if (cookie)
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status event A1=" MACSTR
+ " %sstype=%d cookie=0x%llx%s ack=%d",
+ MAC2STR(hdr->addr1),
+ WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ? "not-mgmt " : "",
+ WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
+ cookie ? "" : "(N/A)", ack != NULL);
+
+ if (cookie_val && cookie_val == drv->eapol_tx_cookie &&
+ len >= ETH_HLEN &&
+ WPA_GET_BE16(frame + 2 * ETH_ALEN) == ETH_P_PAE) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Work around misdelivered control port TX status for EAPOL");
+ nl80211_control_port_frame_tx_status(drv, frame, len, ack,
+ cookie);
+ return;
+ }
+
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+ if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
if (!cookie)
return;
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0x%llx%s (ack=%d)",
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status: cookie=0x%llx%s (ack=%d)",
(long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
+ cookie_val == drv->send_frame_cookie ?
" (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
+ if (cookie_val != drv->send_frame_cookie)
return;
+ } else if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication frame TX status: ack=%d",
+ !!ack);
}
- hdr = (const struct ieee80211_hdr *) frame;
- fc = le_to_host16(hdr->frame_control);
-
os_memset(&event, 0, sizeof(event));
event.tx_status.type = WLAN_FC_GET_TYPE(fc);
event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
@@ -876,6 +1049,23 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
}
+static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ os_memset(&event, 0, sizeof(event));
+ event.unprot_beacon.sa = mgmt->sa;
+ wpa_supplicant_event(drv->ctx, EVENT_UNPROT_BEACON, &event);
+}
+
+
static void mlme_event(struct i802_bss *bss,
enum nl80211_commands cmd, struct nlattr *frame,
struct nlattr *addr, struct nlattr *timed_out,
@@ -957,6 +1147,9 @@ static void mlme_event(struct i802_bss *bss,
mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
nla_data(frame), nla_len(frame));
break;
+ case NL80211_CMD_UNPROT_BEACON:
+ mlme_event_unprot_beacon(drv, nla_data(frame), nla_len(frame));
+ break;
default:
break;
}
@@ -1136,7 +1329,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
struct nlattr *nl;
int rem;
struct scan_info *info;
-#define MAX_REPORT_FREQS 50
+#define MAX_REPORT_FREQS 100
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
@@ -1168,7 +1361,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
}
}
if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
- char msg[300], *pos, *end;
+ char msg[500], *pos, *end;
int res;
pos = msg;
@@ -1221,7 +1414,6 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
enum nl80211_cqm_rssi_threshold_event event;
union wpa_event_data ed;
- struct wpa_signal_info sig;
int res;
if (tb[NL80211_ATTR_CQM] == NULL ||
@@ -1288,19 +1480,27 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
return;
}
- res = nl80211_get_link_signal(drv, &sig);
+ /*
+ * nl80211_get_link_signal() and nl80211_get_link_noise() set default
+ * values in case querying the driver fails.
+ */
+ res = nl80211_get_link_signal(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_signal = sig.current_signal;
- ed.signal_change.current_txrate = sig.current_txrate;
wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
- sig.current_signal, sig.current_txrate);
+ ed.signal_change.current_signal,
+ ed.signal_change.current_txrate);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for signal info failed");
}
- res = nl80211_get_link_noise(drv, &sig);
+ res = nl80211_get_link_noise(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_noise = sig.current_noise;
wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
- sig.current_noise);
+ ed.signal_change.current_noise);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for noise info failed");
}
wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
@@ -1736,35 +1936,73 @@ static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
}
+static unsigned int chan_to_freq(struct wpa_driver_nl80211_data *drv,
+ u8 chan, enum hostapd_hw_mode hw_mode)
+{
+ if (hw_mode == NUM_HOSTAPD_MODES) {
+ /* For drivers that do not report ACS_HW_MODE */
+ u16 num_modes, flags;
+ struct hostapd_hw_modes *modes;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes,
+ &flags, &dfs_domain);
+ if (!modes) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Fetching hardware mode failed");
+ goto try_2_4_or_5;
+ }
+ if (num_modes == 1)
+ hw_mode = modes[0].mode;
+
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+
+ os_free(modes);
+ }
+
+ if (hw_mode == HOSTAPD_MODE_IEEE80211AD) {
+ if (chan >= 1 && chan <= 6)
+ return 56160 + (2160 * chan);
+ return 0;
+ }
+
+try_2_4_or_5:
+ if (chan >= 1 && chan <= 13)
+ return 2407 + 5 * chan;
+ if (chan == 14)
+ return 2484;
+ if (chan >= 36 && chan <= 177)
+ return 5000 + 5 * chan;
+
+ return 0;
+}
+
+
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
union wpa_event_data event;
+ u8 chan;
wpa_printf(MSG_DEBUG,
"nl80211: ACS channel selection vendor event received");
if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
(struct nlattr *) data, len, NULL) ||
- !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
- !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+ (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY] &&
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]) ||
+ (!tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY] &&
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]))
return;
os_memset(&event, 0, sizeof(event));
- event.acs_selected_channels.pri_channel =
- 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]);
+ event.acs_selected_channels.hw_mode = NUM_HOSTAPD_MODES;
+
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
@@ -1779,14 +2017,48 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
}
}
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) {
+ event.acs_selected_channels.pri_freq = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]);
+ } else {
+ chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+ event.acs_selected_channels.pri_freq =
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
+ }
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) {
+ event.acs_selected_channels.sec_freq = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]);
+ } else {
+ chan = nla_get_u8(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+ event.acs_selected_channels.sec_freq =
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
+ }
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL])
+ event.acs_selected_channels.edmg_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
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,
+ "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d",
+ event.acs_selected_channels.pri_freq,
+ event.acs_selected_channels.sec_freq,
event.acs_selected_channels.ch_width,
event.acs_selected_channels.vht_seg0_center_ch,
event.acs_selected_channels.vht_seg1_center_ch,
- event.acs_selected_channels.hw_mode);
+ event.acs_selected_channels.hw_mode,
+ event.acs_selected_channels.edmg_channel);
/* Ignore ACS channel list check for backwards compatibility */
@@ -1831,6 +2103,27 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
}
+static void
+qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ if (!drv->roam_indication_done) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Pending roam indication, delay processing roam+auth vendor event");
+ os_get_reltime(&drv->pending_roam_ind_time);
+
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = os_memdup(data, len);
+ if (!drv->pending_roam_data)
+ return;
+ drv->pending_roam_data_len = len;
+ return;
+ }
+ drv->roam_indication_done = false;
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+}
+
+
static void qca_nl80211_dfs_offload_radar_event(
struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
{
@@ -1980,7 +2273,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv,
}
if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
- char msg[300], *pos, *end;
+ char msg[500], *pos, *end;
int res;
pos = msg;
@@ -2088,7 +2381,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
qca_nl80211_avoid_freq(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
- qca_nl80211_key_mgmt_auth(drv, data, len);
+ qca_nl80211_key_mgmt_auth_handler(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
qca_nl80211_acs_select_ch(drv, data, len);
@@ -2119,6 +2412,87 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
}
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+
+static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[BRCM_VENDOR_ATTR_ACS_LAST + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: BRCM ACS channel selection vendor event received");
+
+ if (nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr *) data,
+ len, NULL) ||
+ !tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ] ||
+ !tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ if (tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ])
+ event.acs_selected_channels.pri_freq =
+ nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]);
+ if (tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ])
+ event.acs_selected_channels.sec_freq =
+ nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]);
+ if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]);
+ if (tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]) {
+ event.acs_selected_channels.hw_mode = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_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",
+ event.acs_selected_channels.hw_mode);
+ return;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
+ event.acs_selected_channels.pri_freq,
+ event.acs_selected_channels.sec_freq,
+ event.acs_selected_channels.ch_width,
+ event.acs_selected_channels.vht_seg0_center_ch,
+ event.acs_selected_channels.vht_seg1_center_ch,
+ event.acs_selected_channels.hw_mode);
+ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
+static void nl80211_vendor_event_brcm(struct wpa_driver_nl80211_data *drv,
+ u32 subcmd, u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "nl80211: Got BRCM vendor event %u", subcmd);
+ switch (subcmd) {
+ case BRCM_VENDOR_EVENT_PRIV_STR:
+ case BRCM_VENDOR_EVENT_HANGED:
+ /* Dump the event on to the console */
+ wpa_msg(NULL, MSG_INFO, "%s", data);
+ break;
+ case BRCM_VENDOR_EVENT_ACS:
+ brcm_nl80211_acs_select_ch(drv, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "%s: Ignore unsupported BRCM vendor event %u",
+ __func__, subcmd);
+ break;
+ }
+}
+
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+
+
static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -2153,10 +2527,21 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
return;
}
+#ifdef ANDROID
+#ifdef ANDROID_LIB_EVENT
+ wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, len);
+#endif /* ANDROID_LIB_EVENT */
+#endif /* ANDROID */
+
switch (vendor_id) {
case OUI_QCA:
nl80211_vendor_event_qca(drv, subcmd, data, len);
break;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ case OUI_BRCM:
+ nl80211_vendor_event_brcm(drv, subcmd, data, len);
+ break;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
break;
@@ -2413,34 +2798,108 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
}
+static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *src_addr;
+ u16 ethertype;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ !tb[NL80211_ATTR_FRAME] ||
+ !tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE])
+ return;
+
+ src_addr = nla_data(tb[NL80211_ATTR_MAC]);
+ ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+
+ switch (ethertype) {
+ case ETH_P_RSN_PREAUTH:
+ wpa_printf(MSG_INFO, "nl80211: Got pre-auth frame from "
+ MACSTR " over control port unexpectedly",
+ MAC2STR(src_addr));
+ break;
+ case ETH_P_PAE:
+ drv_event_eapol_rx(drv->ctx, src_addr,
+ nla_data(tb[NL80211_ATTR_FRAME]),
+ nla_len(tb[NL80211_ATTR_FRAME]));
+ break;
+ default:
+ wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from "
+ MACSTR " over control port",
+ ethertype, MAC2STR(src_addr));
+ break;
+ }
+}
+
+
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie)
+{
+ union wpa_event_data event;
+
+ if (!cookie || len < ETH_HLEN)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Control port TX status (ack=%d), cookie=%llu",
+ ack != NULL, (long long unsigned int) nla_get_u64(cookie));
+
+ os_memset(&event, 0, sizeof(event));
+ event.eapol_tx_status.dst = frame;
+ event.eapol_tx_status.data = frame + ETH_HLEN;
+ event.eapol_tx_status.data_len = len - ETH_HLEN;
+ event.eapol_tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int external_scan_event = 0;
+ struct nlattr *frame = tb[NL80211_ATTR_FRAME];
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
+#ifdef CONFIG_DRIVER_NL80211_QCA
if (cmd == NL80211_CMD_ROAM &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ if (drv->pending_roam_data) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &drv->pending_roam_ind_time, &age);
+ if (age.sec == 0 && age.usec < 100000) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Process pending roam+auth vendor event");
+ qca_nl80211_key_mgmt_auth(
+ drv, drv->pending_roam_data,
+ drv->pending_roam_data_len);
+ }
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = NULL;
+ return;
+ }
/*
* Device will use roam+auth vendor event to indicate
* roaming, so ignore the regular roam event.
*/
+ drv->roam_indication_done = true;
wpa_printf(MSG_DEBUG,
"nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
cmd);
return;
}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
- cmd == NL80211_CMD_SCAN_ABORTED)) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
+ cmd == NL80211_CMD_SCAN_ABORTED))
+ nl80211_restore_ap_mode(bss);
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
@@ -2628,6 +3087,20 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_UPDATE_OWE_INFO:
mlme_event_dh_event(drv, bss, tb);
break;
+ case NL80211_CMD_UNPROT_BEACON:
+ if (frame)
+ mlme_event_unprot_beacon(drv, nla_data(frame),
+ nla_len(frame));
+ break;
+ case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
+ if (!frame)
+ break;
+ nl80211_control_port_frame_tx_status(drv,
+ nla_data(frame),
+ nla_len(frame),
+ tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE]);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -2717,6 +3190,9 @@ int process_bss_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_EXTERNAL_AUTH:
nl80211_external_auth(bss->drv, tb);
break;
+ case NL80211_CMD_CONTROL_PORT_FRAME:
+ nl80211_control_port_frame(bss->drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
diff --git a/contrib/wpa/src/drivers/driver_nl80211_monitor.c b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
index f25cd792464a..7ff55f149a61 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_monitor.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
@@ -71,6 +71,9 @@ static void handle_frame(struct wpa_driver_nl80211_data *drv,
u16 fc;
union wpa_event_data event;
+ if (!drv->use_monitor)
+ return;
+
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
diff --git a/contrib/wpa/src/drivers/driver_nl80211_scan.c b/contrib/wpa/src/drivers/driver_nl80211_scan.c
index 9afa5b304cf8..1316084805a3 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_scan.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_scan.c
@@ -82,7 +82,8 @@ static int nl80211_get_noise_for_scan_results(
os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info,
+ NULL, NULL);
}
@@ -94,7 +95,7 @@ static int nl80211_abort_scan(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -125,7 +126,7 @@ static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_INFO,
@@ -166,11 +167,8 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
- if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED)
+ nl80211_restore_ap_mode(drv->first_bss);
wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@@ -236,6 +234,11 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd,
params->filter_ssids = NULL;
drv->num_filter_ssids = params->num_filter_ssids;
+ if (!drv->hostapd && is_ap_interface(drv->nlmode)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_AP");
+ scan_flags |= NL80211_SCAN_FLAG_AP;
+ }
+
if (params->only_new_results) {
wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
scan_flags |= NL80211_SCAN_FLAG_FLUSH;
@@ -363,7 +366,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
@@ -616,7 +619,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
params->sched_scan_start_delay))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
@@ -653,7 +656,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
#endif /* ANDROID */
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Sched scan stop failed: ret=%d (%s)",
@@ -867,7 +870,7 @@ static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
wpa_driver_nl80211_mlme(drv, addr,
NL80211_CMD_DEAUTHENTICATE,
WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
- NULL);
+ drv->first_bss);
}
}
@@ -928,7 +931,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
struct wpa_scan_results *res;
int ret;
struct nl80211_bss_info_arg arg;
+ int count = 0;
+try_again:
res = os_zalloc(sizeof(*res));
if (res == NULL)
return NULL;
@@ -940,7 +945,19 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
arg.drv = drv;
arg.res = res;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg, NULL, NULL);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump - try again");
+ wpa_scan_results_free(res);
+ goto try_again;
+ }
+ }
if (ret == 0) {
struct nl80211_noise_info info;
@@ -1012,7 +1029,8 @@ void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
ctx.idx = 0;
msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
if (msg)
- send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx,
+ NULL, NULL);
}
@@ -1205,7 +1223,8 @@ int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -1268,7 +1287,7 @@ int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
diff --git a/contrib/wpa/src/drivers/driver_none.c b/contrib/wpa/src/drivers/driver_none.c
new file mode 100644
index 000000000000..ccd2d9da7c9c
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_none.c
@@ -0,0 +1,77 @@
+/*
+ * Driver interface for RADIUS server or WPS ER only (no driver)
+ * Copyright (c) 2008, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "driver.h"
+
+
+struct none_driver_data {
+ struct hostapd_data *hapd;
+ void *ctx;
+};
+
+
+static void * none_driver_hapd_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct none_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct none_driver_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+ "driver data");
+ return NULL;
+ }
+ drv->hapd = hapd;
+
+ return drv;
+}
+
+
+static void none_driver_hapd_deinit(void *priv)
+{
+ struct none_driver_data *drv = priv;
+
+ os_free(drv);
+}
+
+
+static void * none_driver_init(void *ctx, const char *ifname)
+{
+ struct none_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct none_driver_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+ "driver data");
+ return NULL;
+ }
+ drv->ctx = ctx;
+
+ return drv;
+}
+
+
+static void none_driver_deinit(void *priv)
+{
+ struct none_driver_data *drv = priv;
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_none_ops = {
+ .name = "none",
+ .desc = "no driver (RADIUS server/WPS ER)",
+ .hapd_init = none_driver_hapd_init,
+ .hapd_deinit = none_driver_hapd_deinit,
+ .init = none_driver_init,
+ .deinit = none_driver_deinit,
+};
diff --git a/contrib/wpa/src/drivers/driver_openbsd.c b/contrib/wpa/src/drivers/driver_openbsd.c
index c06e75c0f284..bfc231178a2f 100644
--- a/contrib/wpa/src/drivers/driver_openbsd.c
+++ b/contrib/wpa/src/drivers/driver_openbsd.c
@@ -69,14 +69,16 @@ wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
static int
-wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct openbsd_driver_data *drv = priv;
struct ieee80211_keyavail keyavail;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
- if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+ if (key_len > IEEE80211_PMK_LEN ||
+ (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
return -1;
memset(&keyavail, 0, sizeof(keyavail));
diff --git a/contrib/wpa/src/drivers/driver_privsep.c b/contrib/wpa/src/drivers/driver_privsep.c
index 55cf61885741..d6735b49c4af 100644
--- a/contrib/wpa/src/drivers/driver_privsep.c
+++ b/contrib/wpa/src/drivers/driver_privsep.c
@@ -205,14 +205,19 @@ wpa_driver_privsep_get_scan_results2(void *priv)
}
-static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_privsep_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_set_key cmd;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
__func__, priv, alg, key_idx, set_tx);
@@ -225,6 +230,7 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
os_memset(cmd.addr, 0xff, ETH_ALEN);
cmd.key_idx = key_idx;
cmd.set_tx = set_tx;
+ cmd.key_flag = params->key_flag;
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
os_memcpy(cmd.seq, seq, seq_len);
cmd.seq_len = seq_len;
@@ -791,6 +797,8 @@ static int wpa_driver_privsep_get_capa(void *priv,
capa->extended_capa = NULL;
capa->extended_capa_mask = NULL;
capa->extended_capa_len = 0;
+ /* Control port is not yet supported */
+ capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
return 0;
}
diff --git a/contrib/wpa/src/drivers/driver_roboswitch.c b/contrib/wpa/src/drivers/driver_roboswitch.c
new file mode 100644
index 000000000000..9beb6c46d367
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_roboswitch.c
@@ -0,0 +1,487 @@
+/*
+ * WPA Supplicant - roboswitch driver interface
+ * Copyright (c) 2008-2012 Jouke Witteveen
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_ether.h>
+#include <linux/mii.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+
+#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
+
+/* MII access registers */
+#define ROBO_MII_PAGE 0x10 /* MII page register */
+#define ROBO_MII_ADDR 0x11 /* MII address register */
+#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */
+
+#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */
+#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */
+#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */
+#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */
+#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */
+
+/* Page numbers */
+#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */
+#define ROBO_VLAN_PAGE 0x34 /* VLAN page */
+
+/* ARL control page registers */
+#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */
+#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */
+#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */
+#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */
+#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */
+
+/* VLAN page registers */
+#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */
+#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */
+#define ROBO_VLAN_READ 0x0c /* VLAN read register */
+#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_roboswitch_data {
+ void *ctx;
+ struct l2_packet_data *l2;
+ char ifname[IFNAMSIZ + 1];
+ u8 own_addr[ETH_ALEN];
+ struct ifreq ifr;
+ int fd, is_5350;
+ u16 ports;
+};
+
+
+/* Copied from the kernel-only part of mii.h. */
+static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
+{
+ return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+
+
+/*
+ * RoboSwitch uses 16-bit Big Endian addresses.
+ * The ordering of the words is reversed in the MII registers.
+ */
+static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
+{
+ int i;
+ for (i = 0; i < ETH_ALEN; i += 2)
+ be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
+}
+
+
+static u16 wpa_driver_roboswitch_mdio_read(
+ struct wpa_driver_roboswitch_data *drv, u8 reg)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+
+ if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIREG]: %s",
+ strerror(errno));
+ return 0x00;
+ }
+ return mii->val_out;
+}
+
+
+static void wpa_driver_roboswitch_mdio_write(
+ struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+ mii->val_in = val;
+
+ if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSMIIREG]: %s",
+ strerror(errno));
+ }
+}
+
+
+static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u8 op)
+{
+ int i;
+
+ /* set page number */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
+ (page << 8) | ROBO_MII_PAGE_ENABLE);
+ /* set register address */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
+
+ /* check if operation completed */
+ for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
+ if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
+ == 0)
+ return 0;
+ }
+ /* timeout */
+ return -1;
+}
+
+
+static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX ||
+ wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
+ return -1;
+
+ for (i = 0; i < len; ++i) {
+ val[i] = wpa_driver_roboswitch_mdio_read(
+ drv, ROBO_MII_DATA_OFFSET + i);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX) return -1;
+ for (i = 0; i < len; ++i) {
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
+ val[i]);
+ }
+ return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
+}
+
+
+static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
+ os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0)
+ drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14);
+}
+
+
+static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ char *sep;
+
+ if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
+ sep = drv->ifname + os_strlen(drv->ifname);
+ *sep = '.';
+ drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
+ wpa_driver_roboswitch_receive, drv,
+ 1);
+ if (drv->l2 == NULL) {
+ wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
+ __func__, drv->ifname);
+ return -1;
+ }
+ *sep = '\0';
+ l2_packet_get_own_addr(drv->l2, drv->own_addr);
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
+ drv->l2 = NULL;
+ }
+ return 0;
+}
+
+
+static const char * wpa_driver_roboswitch_get_ifname(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ return drv->ifname;
+}
+
+
+static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 read1[3], read2[3], addr_be16[3];
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1) < 0)
+ return -1;
+ if (!(read1[0] & (1 << 4))) {
+ /* multiport addresses are not yet enabled */
+ read1[0] |= 1 << 4;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1);
+ } else {
+ /* if both multiport addresses are the same we can add */
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, read1, 3) ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, read2, 3) ||
+ os_memcmp(read1, read2, 6) != 0)
+ return -1;
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, read1, 1) ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, read2, 1) ||
+ read1[0] != read2[0])
+ return -1;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ }
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 _read, addr_be16[3], addr_read[3], ports_read;
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, &_read, 1) < 0)
+ return -1;
+ /* If ARL control is disabled, there is nothing to leave. */
+ if (!(_read & (1 << 4))) return -1;
+
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_read, 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports_read, 1) < 0)
+ return -1;
+ /* check if we occupy multiport address 1 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read,
+ 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read,
+ 1) < 0)
+ return -1;
+ /* and multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ _read &= ~(1 << 4);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, &_read,
+ 1);
+ } else {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2,
+ &ports_read, 1);
+ }
+ } else {
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read,
+ 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read,
+ 1) < 0)
+ return -1;
+ /* or multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ } else return -1;
+ }
+ return 0;
+}
+
+
+static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_roboswitch_data *drv;
+ char *sep;
+ u16 vlan = 0, _read[2];
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL) return NULL;
+ drv->ctx = ctx;
+ drv->own_addr[0] = '\0';
+
+ /* copy ifname and take a pointer to the second to last character */
+ sep = drv->ifname +
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
+ /* find the '.' separating <interface> and <vlan> */
+ while (sep > drv->ifname && *sep != '.') sep--;
+ if (sep <= drv->ifname) {
+ wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
+ "interface name %s", __func__, drv->ifname);
+ os_free(drv);
+ return NULL;
+ }
+ *sep = '\0';
+ while (*++sep) {
+ if (*sep < '0' || *sep > '9') {
+ wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
+ "in interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ vlan *= 10;
+ vlan += *sep - '0';
+ if (vlan > ROBO_VLAN_MAX) {
+ wpa_printf(MSG_INFO, "%s: VLAN out of range in "
+ "interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->fd < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&drv->ifr, 0, sizeof(drv->ifr));
+ os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIPHY]: %s",
+ strerror(errno));
+ os_free(drv);
+ return NULL;
+ }
+ /* BCM63xx devices provide 0 here */
+ if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR &&
+ if_mii(&drv->ifr)->phy_id != 0) {
+ wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
+ "RoboSwitch?)", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ /* set and read back to see if the register can be used */
+ _read[0] = ROBO_VLAN_MAX;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read + 1, 1);
+ drv->is_5350 = _read[0] == _read[1];
+
+ /* set the read bit */
+ vlan |= 1 << 13;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+ drv->is_5350 ? ROBO_VLAN_ACCESS_5350
+ : ROBO_VLAN_ACCESS,
+ &vlan, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
+ drv->is_5350 ? 2 : 1);
+ if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
+ wpa_printf(MSG_INFO, "%s: Could not get port information for "
+ "VLAN %d", __func__, vlan & ~(1 << 13));
+ os_free(drv);
+ return NULL;
+ }
+ drv->ports = _read[0] & 0x001F;
+ /* add the MII port */
+ drv->ports |= 1 << 8;
+ if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
+ os_free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
+ "RoboSwitch ARL", __func__);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_roboswitch_deinit(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (drv->l2) {
+ l2_packet_deinit(drv->l2);
+ drv->l2 = NULL;
+ }
+ if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
+ __func__);
+ }
+
+ close(drv->fd);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
+ .name = "roboswitch",
+ .desc = "wpa_supplicant roboswitch driver",
+ .get_ssid = wpa_driver_roboswitch_get_ssid,
+ .get_bssid = wpa_driver_roboswitch_get_bssid,
+ .get_capa = wpa_driver_roboswitch_get_capa,
+ .init = wpa_driver_roboswitch_init,
+ .deinit = wpa_driver_roboswitch_deinit,
+ .set_param = wpa_driver_roboswitch_set_param,
+ .get_ifname = wpa_driver_roboswitch_get_ifname,
+};
diff --git a/contrib/wpa/src/drivers/driver_wext.c b/contrib/wpa/src/drivers/driver_wext.c
new file mode 100644
index 000000000000..0f0ad1f537fa
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wext.c
@@ -0,0 +1,2499 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * 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.
+ *
+ * This file implements a driver interface for the Linux Wireless Extensions.
+ * When used with WE-18 or newer, this interface can be used as-is with number
+ * of drivers. In addition to this, some of the common functions in this file
+ * can be used by other driver interface implementations that use generic WE
+ * ioctls, but require private ioctls for some of the functionality.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+#include <dirent.h>
+
+#include "linux_wext.h"
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "rfkill.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+static int wpa_driver_wext_flush_pmkid(void *priv);
+static int wpa_driver_wext_get_range(void *priv);
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
+
+
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: Buffer for BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno));
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Buffer for the SSID; must be at least 32 bytes long
+ * Returns: SSID length on success, -1 on failure
+ */
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ 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 = SSID_MAX_LEN;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+ strerror(errno));
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ 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
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: SSID
+ * @ssid_len: Length of SSID (0..32)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > SSID_MAX_LEN)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @freq: Frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+ u8 *req_ies = NULL, *resp_ies = NULL;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ req_ies = os_malloc(bytes);
+ if (req_ies == NULL ||
+ hexstr2bin(spos, req_ies, bytes) < 0)
+ goto done;
+ data.assoc_info.req_ies = req_ies;
+ data.assoc_info.req_ies_len = bytes;
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ resp_ies = os_malloc(bytes);
+ if (resp_ies == NULL ||
+ hexstr2bin(spos, resp_ies, bytes) < 0)
+ goto done;
+ data.assoc_info.resp_ies = resp_ies;
+ data.assoc_info.resp_ies_len = bytes;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(resp_ies);
+ os_free(req_ies);
+ }
+}
+
+
+static int wpa_driver_wext_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_pmkidcand(
+ struct wpa_driver_wext_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocreqie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_memdup(ev, len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocrespie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_memdup(ev, len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+}
+
+
+static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
+ char *data, unsigned int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while ((size_t) (end - pos) >= IW_EV_LCP_LEN) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_wext_event_assoc_ies(drv);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
+ NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ if (iwe->u.data.length > end - custom) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVMICHAELMICFAILURE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_michaelmicfailure(
+ drv->ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (iwe->u.data.length > end - custom) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVCUSTOM length");
+ return;
+ }
+ buf = dup_binstr(custom, iwe->u.data.length);
+ if (buf == NULL)
+ return;
+ wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
+ os_free(buf);
+ break;
+ case SIOCGIWSCAN:
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
+ drv, drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
+ break;
+ case IWEVASSOCREQIE:
+ if (iwe->u.data.length > end - custom) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCREQIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ if (iwe->u.data.length > end - custom) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCRESPIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ if (iwe->u.data.length > end - custom) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVPMKIDCAND length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
+ char *buf, size_t len, int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (del) {
+ if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already set - ignore event");
+ return;
+ }
+ drv->if_removed = 1;
+ } else {
+ if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
+ "does not exist - ignore "
+ "RTM_NEWLINK",
+ drv->ifname);
+ return;
+ }
+ if (!drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already cleared - ignore event");
+ return;
+ }
+ drv->if_removed = 0;
+ }
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
+ u8 *buf, size_t len)
+{
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
+ int ifindex, u8 *buf, size_t len)
+{
+ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
+ drv->ifindex = if_nametoindex(drv->ifname);
+ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
+ "interface");
+ wpa_driver_wext_finish_drv_init(drv);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+ char namebuf[IFNAMSIZ];
+
+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface down");
+ drv->if_disabled = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+ }
+
+ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is down",
+ namebuf);
+ } else if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s does not exist",
+ drv->ifname);
+ } else if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is marked "
+ "removed", drv->ifname);
+ } else {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+ drv->if_disabled = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ }
+
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_wext_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ -1, IF_OPER_UP);
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_wext_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len)
+{
+ struct wpa_driver_wext_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
+
+ attrlen = len;
+ attr = (struct rtattr *) buf;
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_rfkill_blocked(void *ctx)
+{
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+ /*
+ * This may be for any interface; use ifdown event to disable
+ * interface.
+ */
+}
+
+
+static void wpa_driver_wext_rfkill_unblocked(void *ctx)
+{
+ struct wpa_driver_wext_data *drv = ctx;
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked");
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP "
+ "after rfkill unblock");
+ return;
+ }
+ /* rtnetlink ifup handler will report interface as enabled */
+}
+
+
+static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
+{
+ /* Find phy (radio) to which this interface belongs */
+ char buf[90], *pos;
+ int f, rv;
+
+ drv->phyname[0] = '\0';
+ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+ drv->ifname);
+ f = open(buf, O_RDONLY);
+ if (f < 0) {
+ wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+ buf, strerror(errno));
+ return;
+ }
+
+ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+ close(f);
+ if (rv < 0) {
+ wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+ buf, strerror(errno));
+ return;
+ }
+
+ drv->phyname[rv] = '\0';
+ pos = os_strchr(drv->phyname, '\n');
+ if (pos)
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
+ drv->ifname, drv->phyname);
+}
+
+
+/**
+ * wpa_driver_wext_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_wext_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_wext_data *drv;
+ struct netlink_config *cfg;
+ struct rfkill_config *rcfg;
+ char path[128];
+ struct stat buf;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
+ if (stat(path, &buf) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
+ drv->cfg80211 = 1;
+ wext_get_phy_name(drv);
+ }
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s",
+ strerror(errno));
+ goto err1;
+ }
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto err1;
+ cfg->ctx = drv;
+ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
+ goto err2;
+ }
+
+ rcfg = os_zalloc(sizeof(*rcfg));
+ if (rcfg == NULL)
+ goto err3;
+ rcfg->ctx = drv;
+ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
+ rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
+ rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
+ drv->rfkill = rfkill_init(rcfg);
+ if (drv->rfkill == NULL) {
+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
+ os_free(rcfg);
+ }
+
+ drv->mlme_sock = -1;
+
+ if (wpa_driver_wext_finish_drv_init(drv) < 0)
+ goto err3;
+
+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
+
+ return drv;
+
+err3:
+ rfkill_deinit(drv->rfkill);
+ netlink_deinit(drv->netlink);
+err2:
+ close(drv->ioctl_sock);
+err1:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
+static int wext_hostap_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ char buf[200], *res;
+ int type, ret;
+ FILE *f;
+
+ if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
+ return -1;
+
+ ret = snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+ drv->ifname, ifname);
+ if (os_snprintf_error(sizeof(buf), ret))
+ return -1;
+
+ 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 path[200], 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(path, sizeof(path), "/sys/class/net/%s/device/driver",
+ drv->ifname);
+ res = readlink(path, 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;
+ int i;
+
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
+ if (rfkill_is_blocked(drv->rfkill)) {
+ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
+ "interface '%s' due to rfkill",
+ drv->ifname);
+ drv->if_disabled = 1;
+ send_rfkill_event = 1;
+ } else {
+ wpa_printf(MSG_ERROR, "WEXT: Could not set "
+ "interface '%s' UP", drv->ifname);
+ return -1;
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_wext_flush_pmkid(drv);
+
+ if (wpa_driver_wext_set_mode(drv, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not configure driver to use "
+ "managed mode");
+ /* Try to use it anyway */
+ }
+
+ wpa_driver_wext_get_range(drv);
+
+ /* Update per interface supported AKMs */
+ for (i = 0; i < WPA_IF_MAX; i++)
+ drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
+
+ /*
+ * Unlock the driver's BSSID and force to a random SSID to clear any
+ * previous association the driver might have when the supplicant
+ * starts up.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ wext_check_hostap(drv);
+
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ 1, IF_OPER_DORMANT);
+
+ if (send_rfkill_event) {
+ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
+ drv, drv->ctx);
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_driver_wext_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_wext_init().
+ */
+void wpa_driver_wext_deinit(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+
+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
+
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_wext_send_rfkill, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+ netlink_deinit(drv->netlink);
+ rfkill_deinit(drv->rfkill);
+
+ if (drv->mlme_sock >= 0)
+ eloop_unregister_read_sock(drv->mlme_sock);
+
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
+
+ close(drv->ioctl_sock);
+ if (drv->mlme_sock >= 0)
+ close(drv->mlme_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_wext_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0, timeout;
+ struct iw_scan_req req;
+ const u8 *ssid = params->ssids[0].ssid;
+ size_t ssid_len = params->ssids[0].ssid_len;
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ssid && ssid_len) {
+ os_memset(&req, 0, sizeof(req));
+ req.essid_len = ssid_len;
+ req.bssid.sa_family = ARPHRD_ETHER;
+ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+ os_memcpy(req.essid, ssid, ssid_len);
+ iwr.u.data.pointer = (caddr_t) &req;
+ iwr.u.data.length = sizeof(req);
+ iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
+ size_t *len)
+{
+ struct iwreq iwr;
+ u8 *res_buf;
+ size_t res_buf_len;
+
+ res_buf_len = IW_SCAN_MAX_DATA;
+ for (;;) {
+ res_buf = os_malloc(res_buf_len);
+ if (res_buf == NULL)
+ return NULL;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = res_buf;
+ iwr.u.data.length = res_buf_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+ break;
+
+ if (errno == E2BIG && res_buf_len < 65535) {
+ os_free(res_buf);
+ res_buf = NULL;
+ res_buf_len *= 2;
+ if (res_buf_len > 65535)
+ res_buf_len = 65535; /* 16-bit length field */
+ wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+ "trying larger buffer (%lu bytes)",
+ (unsigned long) res_buf_len);
+ } else {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s",
+ strerror(errno));
+ os_free(res_buf);
+ return NULL;
+ }
+ }
+
+ if (iwr.u.data.length > res_buf_len) {
+ os_free(res_buf);
+ return NULL;
+ }
+ *len = iwr.u.data.length;
+
+ return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+ struct wpa_scan_res res;
+ u8 *ie;
+ size_t ie_len;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+ int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (iwe->u.mode == IW_MODE_ADHOC)
+ res->res.caps |= IEEE80211_CAP_IBSS;
+ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+ res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ int ssid_len = iwe->u.essid.length;
+ if (ssid_len > end - custom)
+ return;
+ if (iwe->u.essid.flags &&
+ ssid_len > 0 &&
+ ssid_len <= IW_ESSID_MAX_SIZE) {
+ os_memcpy(res->ssid, custom, ssid_len);
+ res->ssid_len = ssid_len;
+ }
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ int divi = 1000000, i;
+
+ if (iwe->u.freq.e == 0) {
+ /*
+ * Some drivers do not report frequency, but a channel.
+ * Try to map this to frequency by assuming they are using
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
+ */
+
+ if (res->res.freq)
+ return;
+
+ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+ res->res.freq = 2407 + 5 * iwe->u.freq.m;
+ return;
+ } else if (iwe->u.freq.m == 14) {
+ res->res.freq = 2484;
+ return;
+ }
+ }
+
+ if (iwe->u.freq.e > 6) {
+ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+ MACSTR " m=%d e=%d)",
+ MAC2STR(res->res.bssid), iwe->u.freq.m,
+ iwe->u.freq.e);
+ return;
+ }
+
+ for (i = 0; i < iwe->u.freq.e; i++)
+ divi /= 10;
+ res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
+ struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ res->res.qual = iwe->u.qual.qual;
+ res->res.noise = iwe->u.qual.noise;
+ res->res.level = iwe->u.qual.level;
+ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
+ res->res.flags |= WPA_SCAN_QUAL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
+ res->res.flags |= WPA_SCAN_LEVEL_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
+ res->res.flags |= WPA_SCAN_NOISE_INVALID;
+ if (iwe->u.qual.updated & IW_QUAL_DBM)
+ res->res.flags |= WPA_SCAN_LEVEL_DBM;
+ if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
+ ((iwe->u.qual.level != 0) &&
+ (iwe->u.qual.level > drv->max_level))) {
+ if (iwe->u.qual.level >= 64)
+ res->res.level -= 0x100;
+ if (iwe->u.qual.noise >= 64)
+ res->res.noise -= 0x100;
+ }
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+ res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+ struct wext_scan_data *res, char *pos,
+ char *end)
+{
+ int maxrate;
+ char *custom = pos + IW_EV_LCP_LEN;
+ struct iw_param p;
+ size_t clen;
+
+ clen = iwe->len;
+ if (clen > (size_t) (end - custom))
+ return;
+ maxrate = 0;
+ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+ /* Note: may be misaligned, make a local, aligned copy */
+ os_memcpy(&p, custom, sizeof(struct iw_param));
+ if (p.value > maxrate)
+ maxrate = p.value;
+ clen -= sizeof(struct iw_param);
+ custom += sizeof(struct iw_param);
+ }
+
+ /* Convert the maxrate from WE-style (b/s units) to
+ * 802.11 rates (500000 b/s units).
+ */
+ res->maxrate = maxrate / 500000;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ char *genie, *gpos, *gend;
+ u8 *tmp;
+
+ if (iwe->u.data.length == 0)
+ return;
+
+ gpos = genie = custom;
+ gend = genie + iwe->u.data.length;
+ if (gend > end) {
+ wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+ return;
+ }
+
+ tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+ if (tmp == NULL)
+ return;
+ os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+ res->ie = tmp;
+ res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ size_t clen;
+ u8 *tmp;
+
+ clen = iwe->u.data.length;
+ if (clen > (size_t) (end - custom))
+ return;
+
+ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
+ res->ie_len += bytes;
+ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ res->ie = tmp;
+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+ return;
+ res->ie_len += bytes;
+ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+ char *spos;
+ int bytes;
+ u8 bin[8];
+ spos = custom + 4;
+ bytes = custom + clen - spos;
+ if (bytes != 16) {
+ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+ return;
+ }
+ bytes /= 2;
+ if (hexstr2bin(spos, bin, bytes) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
+ return;
+ }
+ res->res.tsf += WPA_GET_BE64(bin);
+ }
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
+{
+ return drv->we_version_compiled > 18 &&
+ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+ cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
+ struct wext_scan_data *data)
+{
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ size_t extra_len;
+ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+ /* Figure out whether we need to fake any IEs */
+ pos = data->ie;
+ end = pos + data->ie_len;
+ while (pos && end - pos > 1) {
+ if (2 + pos[1] > end - pos)
+ break;
+ if (pos[0] == WLAN_EID_SSID)
+ ssid_ie = pos;
+ else if (pos[0] == WLAN_EID_SUPP_RATES)
+ rate_ie = pos;
+ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+ rate_ie = pos;
+ pos += 2 + pos[1];
+ }
+
+ extra_len = 0;
+ if (ssid_ie == NULL)
+ extra_len += 2 + data->ssid_len;
+ if (rate_ie == NULL && data->maxrate)
+ extra_len += 3;
+
+ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+ if (r == NULL)
+ return;
+ os_memcpy(r, &data->res, sizeof(*r));
+ r->ie_len = extra_len + data->ie_len;
+ pos = (u8 *) (r + 1);
+ if (ssid_ie == NULL) {
+ /*
+ * Generate a fake SSID IE since the driver did not report
+ * a full IE list.
+ */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = data->ssid_len;
+ os_memcpy(pos, data->ssid, data->ssid_len);
+ pos += data->ssid_len;
+ }
+ if (rate_ie == NULL && data->maxrate) {
+ /*
+ * Generate a fake Supported Rates IE since the driver did not
+ * report a full IE list.
+ */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = 1;
+ *pos++ = data->maxrate;
+ }
+ if (data->ie)
+ os_memcpy(pos, data->ie, data->ie_len);
+
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+}
+
+
+/**
+ * wpa_driver_wext_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ size_t len;
+ int first;
+ u8 *res_buf;
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom;
+ struct wpa_scan_results *res;
+ struct wext_scan_data data;
+
+ res_buf = wpa_driver_wext_giwscan(drv, &len);
+ if (res_buf == NULL)
+ return NULL;
+
+ first = 1;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL) {
+ os_free(res_buf);
+ return NULL;
+ }
+
+ pos = (char *) res_buf;
+ end = (char *) res_buf + len;
+ os_memset(&data, 0, sizeof(data));
+
+ while ((size_t) (end - pos) >= IW_EV_LCP_LEN) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
+ break;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (wext_19_iw_point(drv, iwe->cmd)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ first = 0;
+ os_free(data.ie);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.res.bssid,
+ iwe->u.ap_addr.sa_data, ETH_ALEN);
+ break;
+ case SIOCGIWMODE:
+ wext_get_scan_mode(iwe, &data);
+ break;
+ case SIOCGIWESSID:
+ wext_get_scan_ssid(iwe, &data, custom, end);
+ break;
+ case SIOCGIWFREQ:
+ wext_get_scan_freq(iwe, &data);
+ break;
+ case IWEVQUAL:
+ wext_get_scan_qual(drv, iwe, &data);
+ break;
+ case SIOCGIWENCODE:
+ wext_get_scan_encode(iwe, &data);
+ break;
+ case SIOCGIWRATE:
+ wext_get_scan_rate(iwe, &data, pos, end);
+ break;
+ case IWEVGENIE:
+ wext_get_scan_iwevgenie(iwe, &data, custom, end);
+ break;
+ case IWEVCUSTOM:
+ wext_get_scan_custom(iwe, &data, custom, end);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+ os_free(res_buf);
+ res_buf = NULL;
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ os_free(data.ie);
+
+ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+ (unsigned long) len, (unsigned long) res->num);
+
+ return res;
+}
+
+
+static int wpa_driver_wext_get_range(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ drv->capa.max_scan_ssids = 1;
+
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ drv->max_level = range->max_qual.level;
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
+ const u8 *psk)
+{
+ struct iw_encode_ext *ext;
+ struct iwreq iwr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
+ return 0;
+
+ if (!psk)
+ return 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ ext = os_zalloc(sizeof(*ext) + PMK_LEN);
+ if (ext == NULL)
+ return -1;
+
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
+ ext->key_len = PMK_LEN;
+ os_memcpy(&ext->key, psk, ext->key_len);
+ ext->alg = IW_ENCODE_ALG_PMK;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s",
+ strerror(errno));
+ os_free(ext);
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq,
+ size_t seq_len,
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ struct iw_encode_ext *ext;
+
+ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
+ __FUNCTION__, (unsigned long) seq_len);
+ return -1;
+ }
+
+ ext = os_zalloc(sizeof(*ext) + key_len);
+ if (ext == NULL)
+ return -1;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + key_len;
+
+ if (addr == NULL || is_broadcast_ether_addr(addr))
+ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
+ if (set_tx)
+ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
+
+ ext->addr.sa_family = ARPHRD_ETHER;
+ if (addr)
+ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
+ else
+ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
+ if (key && key_len) {
+ os_memcpy(ext + 1, key, key_len);
+ ext->key_len = key_len;
+ }
+ if (key_flag & KEY_FLAG_PMK) {
+ ext->alg = IW_ENCODE_ALG_PMK;
+ } else {
+ switch (alg) {
+ case WPA_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
+ break;
+ case WPA_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ break;
+ case WPA_ALG_BIP_CMAC_128:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+ __FUNCTION__, alg);
+ os_free(ext);
+ return -1;
+ }
+ }
+
+ if (seq && seq_len) {
+ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
+ os_memcpy(ext->rx_seq, seq, seq_len);
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ if (errno == ENODEV) {
+ /*
+ * ndiswrapper seems to be returning incorrect error
+ * code.. */
+ ret = -2;
+ }
+
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s",
+ strerror(errno));
+ }
+
+ os_free(ext);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_key - Configure encryption key
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @params: Key parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function uses SIOCSIWENCODEEXT by default, but tries to use
+ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
+ */
+static int wpa_driver_wext_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ enum wpa_alg alg = params->alg;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu",
+ __FUNCTION__, alg, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len, key_flag);
+ if (ret == 0)
+ return 0;
+
+ if (ret == -2 &&
+ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
+ ret = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT");
+ return ret;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) key;
+ iwr.u.encoding.length = key_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "ioctl[SIOCSIWENCODE] (set_tx): %s",
+ strerror(errno));
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_wext_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
+ const u8 *addr, int cmd, u16 reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+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[SSID_MAX_LEN];
+ int i;
+
+ /*
+ * Only force-disconnect when the card is in infrastructure mode,
+ * otherwise the driver might interpret the cleared BSSID and random
+ * SSID as an attempt to create a new ad-hoc network.
+ */
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
+ iwr.u.mode = IW_MODE_INFRA;
+ }
+
+ if (iwr.u.mode == IW_MODE_INFRA) {
+ /* Clear the BSSID selection */
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+ "selection on disconnect");
+ }
+
+ if (drv->cfg80211) {
+ /*
+ * cfg80211 supports SIOCSIWMLME commands, so there is
+ * no need for the random SSID hack, but clear the
+ * SSID.
+ */
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
+ "SSID on disconnect");
+ }
+ return;
+ }
+
+ /*
+ * Set a random SSID to make sure the driver will not be trying
+ * to associate with something even if it does not understand
+ * SIOCSIWMLME commands (or tries to associate automatically
+ * after deauth/disassoc).
+ */
+ for (i = 0; i < SSID_MAX_LEN; i++)
+ ssid[i] = rand() & 0xFF;
+ if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
+ "SSID to disconnect");
+ }
+ }
+}
+
+
+static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
+ u16 reason_code)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case WPA_CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case WPA_CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case WPA_CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case WPA_CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case WPA_KEY_MGMT_IEEE8021X:
+ case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case WPA_KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->cfg80211) {
+ /*
+ * Stop cfg80211 from trying to associate before we are done
+ * with all parameters.
+ */
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)");
+ /* continue anyway */
+ }
+ }
+
+ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
+ < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_proto & WPA_PROTO_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else if (params->wpa_proto & WPA_PROTO_WPA)
+ value = IW_AUTH_WPA_VERSION_WPA;
+ else
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
+ params->pairwise_suite != WPA_CIPHER_NONE ||
+ params->group_suite != WPA_CIPHER_NONE ||
+ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA));
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+ switch (params->mgmt_frame_protection) {
+ case NO_MGMT_FRAME_PROTECTION:
+ value = IW_AUTH_MFP_DISABLED;
+ break;
+ case MGMT_FRAME_PROTECTION_OPTIONAL:
+ value = IW_AUTH_MFP_OPTIONAL;
+ break;
+ case MGMT_FRAME_PROTECTION_REQUIRED:
+ value = IW_AUTH_MFP_REQUIRED;
+ break;
+ };
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
+ ret = -1;
+ if (params->freq.freq &&
+ wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
+ ret = -1;
+ if (!drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+ if (drv->cfg80211 &&
+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & WPA_AUTH_ALG_OPEN)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & WPA_AUTH_ALG_SHARED)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & WPA_AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = -1;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
+
+ if (errno != EBUSY) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
+ else
+ ret = 0;
+
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
+ }
+
+done:
+ return ret;
+}
+
+
+static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s",
+ strerror(errno));
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_add_pmkid(void *priv,
+ struct wpa_pmkid_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, params->bssid,
+ params->pmkid);
+}
+
+
+static int wpa_driver_wext_remove_pmkid(void *priv,
+ struct wpa_pmkid_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, params->bssid,
+ params->pmkid);
+}
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ if (ifname == NULL) {
+ drv->ifindex2 = -1;
+ return 0;
+ }
+
+ drv->ifindex2 = if_nametoindex(ifname);
+ if (drv->ifindex2 <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
+ "wireless events", drv->ifindex2, ifname);
+
+ return 0;
+}
+
+
+int wpa_driver_wext_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_wext_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+ state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
+{
+ return drv->we_version_compiled;
+}
+
+
+static const char * wext_get_radio_name(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return drv->phyname;
+}
+
+
+static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_statistics stats;
+ struct iwreq iwr;
+
+ os_memset(si, 0, sizeof(*si));
+ si->current_signal = -WPA_INVALID_NOISE;
+ si->current_noise = WPA_INVALID_NOISE;
+ si->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) &stats;
+ iwr.u.data.length = sizeof(stats);
+ iwr.u.data.flags = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ si->current_signal = stats.qual.level -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ si->current_noise = stats.qual.noise -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ return 0;
+}
+
+
+static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int res;
+ char *pos, *end;
+ unsigned char addr[ETH_ALEN];
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr))
+ return -1;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "addr=" MACSTR "\n",
+ drv->ifindex,
+ drv->ifname,
+ MAC2STR(addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
+const struct wpa_driver_ops wpa_driver_wext_ops = {
+ .name = "wext",
+ .desc = "Linux wireless extensions (generic)",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .set_key = wpa_driver_wext_set_key,
+ .set_countermeasures = wpa_driver_wext_set_countermeasures,
+ .scan2 = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .deauthenticate = wpa_driver_wext_deauthenticate,
+ .associate = wpa_driver_wext_associate,
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .add_pmkid = wpa_driver_wext_add_pmkid,
+ .remove_pmkid = wpa_driver_wext_remove_pmkid,
+ .flush_pmkid = wpa_driver_wext_flush_pmkid,
+ .get_capa = wpa_driver_wext_get_capa,
+ .set_operstate = wpa_driver_wext_set_operstate,
+ .get_radio_name = wext_get_radio_name,
+ .signal_poll = wpa_driver_wext_signal_poll,
+ .status = wpa_driver_wext_status,
+};
diff --git a/contrib/wpa/src/drivers/driver_wext.h b/contrib/wpa/src/drivers/driver_wext.h
new file mode 100644
index 000000000000..6214cdf42a68
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wext.h
@@ -0,0 +1,77 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_WEXT_H
+#define DRIVER_WEXT_H
+
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+ void *ctx;
+ struct netlink_data *netlink;
+ int ioctl_sock;
+ int mlme_sock;
+ char ifname[IFNAMSIZ + 1];
+ char phyname[32];
+ int ifindex;
+ int ifindex2;
+ int if_removed;
+ int if_disabled;
+ struct rfkill_data *rfkill;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+
+ int cfg80211; /* whether driver is using cfg80211 */
+
+ u8 max_level;
+};
+
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_wext_set_freq(void *priv, int freq);
+int wpa_driver_wext_set_mode(void *priv, int mode);
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
+
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname);
+
+void * wpa_driver_wext_init(void *ctx, const char *ifname);
+void wpa_driver_wext_deinit(void *priv);
+
+int wpa_driver_wext_set_operstate(void *priv, int state);
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
+#endif /* DRIVER_WEXT_H */
diff --git a/contrib/wpa/src/drivers/drivers.mak b/contrib/wpa/src/drivers/drivers.mak
new file mode 100644
index 000000000000..a03d4a034511
--- /dev/null
+++ b/contrib/wpa/src/drivers/drivers.mak
@@ -0,0 +1,220 @@
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
+
+##### COMMON DRIVERS
+
+ifdef CONFIG_DRIVER_WIRED
+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
+DRV_OBJS += ../src/drivers/driver_wired.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += ../src/drivers/driver_macsec_linux.o
+NEED_DRV_WIRED_COMMON=1
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_QCA
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
+DRV_OBJS += ../src/drivers/driver_macsec_qca.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += ../src/drivers/driver_wired_common.o
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
+DRV_OBJS += ../src/drivers/driver_nl80211.o
+DRV_OBJS += ../src/drivers/driver_nl80211_capa.o
+DRV_OBJS += ../src/drivers/driver_nl80211_event.o
+DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
+DRV_OBJS += ../src/drivers/driver_nl80211_scan.o
+ifdef CONFIG_DRIVER_NL80211_QCA
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
+endif
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+NEED_RADIOTAP=y
+NEED_LIBNL=y
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += ../src/drivers/driver_bsd.o
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += ../src/drivers/driver_openbsd.o
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += ../src/drivers/driver_none.o
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += ../src/drivers/driver_atheros.o
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+ifdef ATH_GCM_SUPPORT
+CFLAGS += -DATH_GCM_SUPPORT
+endif
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += ../src/drivers/driver_wext.o
+NEED_RFKILL=y
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += ../src/drivers/netlink.o
+endif
+
+ifdef NEED_RFKILL
+DRV_OBJS += ../src/drivers/rfkill.o
+endif
+
+ifdef NEED_RADIOTAP
+DRV_OBJS += ../src/utils/radiotap.o
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LINUX_IOCTL=y
+ifdef CONFIG_VLAN_NETLINK
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += ../src/drivers/linux_ioctl.o
+endif
+
+ifdef NEED_LIBNL
+ifndef CONFIG_LIBNL32
+ifndef CONFIG_LIBNL20
+ifndef CONFIG_LIBNL_TINY
+PKG_CONFIG ?= pkg-config
+HAVE_LIBNL3 := $(shell $(PKG_CONFIG) --exists libnl-3.0; echo $$?)
+ifeq ($(HAVE_LIBNL3),0)
+CONFIG_LIBNL32=y
+endif
+endif
+endif
+endif
+
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ ifdef LIBNL_INC
+ DRV_CFLAGS += -I$(LIBNL_INC)
+ else
+ PKG_CONFIG ?= pkg-config
+ DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
+ endif
+ ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+ endif
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ ifndef CONFIG_OSX
+ DRV_LIBS += -lnl
+ DRV_LIBS += -lnl-genl
+ endif
+ endif
+endif
+endif
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)
diff --git a/contrib/wpa/src/drivers/drivers.mk b/contrib/wpa/src/drivers/drivers.mk
new file mode 100644
index 000000000000..10eab6a92e17
--- /dev/null
+++ b/contrib/wpa/src/drivers/drivers.mk
@@ -0,0 +1,196 @@
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
+
+##### COMMON DRIVERS
+
+ifdef CONFIG_DRIVER_WIRED
+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
+DRV_OBJS += src/drivers/driver_wired.c
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += src/drivers/driver_macsec_linux.c
+NEED_DRV_WIRED_COMMON=1
+CONFIG_LIBNL3_ROUTE=y
+NEED_LIBNL=y
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += src/drivers/driver_wired_common.c
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
+DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/drivers/driver_nl80211_android.c
+DRV_OBJS += src/drivers/driver_nl80211_capa.c
+DRV_OBJS += src/drivers/driver_nl80211_event.c
+DRV_OBJS += src/drivers/driver_nl80211_monitor.c
+DRV_OBJS += src/drivers/driver_nl80211_scan.c
+ifdef CONFIG_DRIVER_NL80211_QCA
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
+endif
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+NEED_RADIOTAP=y
+NEED_LIBNL=y
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += src/drivers/driver_bsd.c
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += src/drivers/driver_openbsd.c
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += src/drivers/driver_none.c
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += src/drivers/driver_atheros.c
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += src/drivers/driver_ndis.c
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += src/drivers/driver_ndis_.c
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += src/drivers/driver_wext.c
+NEED_RFKILL=y
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += src/drivers/netlink.c
+endif
+
+ifdef NEED_RFKILL
+DRV_OBJS += src/drivers/rfkill.c
+endif
+
+ifdef NEED_RADIOTAP
+DRV_OBJS += src/utils/radiotap.c
+endif
+
+ifdef CONFIG_DRIVER_CUSTOM
+DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LINUX_IOCTL=y
+ifdef CONFIG_VLAN_NETLINK
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += src/drivers/linux_ioctl.c
+endif
+
+ifdef NEED_LIBNL
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_CFLAGS += -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ DRV_LIBS += -lnl-genl
+ endif
+endif
+endif
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)
diff --git a/contrib/wpa/src/drivers/linux_ioctl.c b/contrib/wpa/src/drivers/linux_ioctl.c
new file mode 100644
index 000000000000..7edb9df2edd4
--- /dev/null
+++ b/contrib/wpa/src/drivers/linux_ioctl.c
@@ -0,0 +1,237 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include "utils/common.h"
+#include "common/linux_bridge.h"
+#include "linux_ioctl.h"
+
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
+{
+ struct ifreq ifr;
+ int ret;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
+ wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+ ifname, strerror(errno));
+ return ret;
+ }
+
+ if (dev_up) {
+ if (ifr.ifr_flags & IFF_UP)
+ return 0;
+ ifr.ifr_flags |= IFF_UP;
+ } else {
+ if (!(ifr.ifr_flags & IFF_UP))
+ return 0;
+ ifr.ifr_flags &= ~IFF_UP;
+ }
+
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
+ wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+ "%s",
+ ifname, dev_up ? "UP" : "DOWN", strerror(errno));
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int linux_iface_up(int sock, const char *ifname)
+{
+ struct ifreq ifr;
+ int ret;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
+ wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+ ifname, strerror(errno));
+ return ret;
+ }
+
+ return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
+ wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
+ ifname, ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+
+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
+ wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_add(int sock, const char *brname)
+{
+ if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
+ int saved_errno = errno;
+
+ wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
+ brname, strerror(errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_del(int sock, const char *brname)
+{
+ if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
+ brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_add_if(int sock, const char *brname, const char *ifname)
+{
+ struct ifreq ifr;
+ int ifindex;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_ifindex = ifindex;
+ if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
+ int saved_errno = errno;
+
+ wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
+ "%s: %s", ifname, brname, strerror(errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_del_if(int sock, const char *brname, const char *ifname)
+{
+ struct ifreq ifr;
+ int ifindex;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_ifindex = ifindex;
+ if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
+ "bridge %s: %s", ifname, brname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int linux_br_get(char *brname, const char *ifname)
+{
+ char path[128], brlink[128], *pos;
+ ssize_t res;
+
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
+ ifname);
+ res = readlink(path, brlink, sizeof(brlink));
+ if (res < 0 || (size_t) res >= sizeof(brlink))
+ return -1;
+ brlink[res] = '\0';
+ pos = os_strrchr(brlink, '/');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ os_strlcpy(brname, pos, IFNAMSIZ);
+ return 0;
+}
+
+
+int linux_master_get(char *master_ifname, const char *ifname)
+{
+ char buf[128], masterlink[128], *pos;
+ ssize_t res;
+
+ /* check whether there is a master */
+ os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
+
+ res = readlink(buf, masterlink, sizeof(masterlink));
+ if (res < 0 || (size_t) res >= sizeof(masterlink))
+ return -1;
+
+ masterlink[res] = '\0';
+
+ pos = os_strrchr(masterlink, '/');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ os_strlcpy(master_ifname, pos, IFNAMSIZ);
+ return 0;
+}
diff --git a/contrib/wpa/src/drivers/linux_ioctl.h b/contrib/wpa/src/drivers/linux_ioctl.h
new file mode 100644
index 000000000000..6de4d9b88275
--- /dev/null
+++ b/contrib/wpa/src/drivers/linux_ioctl.h
@@ -0,0 +1,23 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_IOCTL_H
+#define LINUX_IOCTL_H
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
+int linux_br_add(int sock, const char *brname);
+int linux_br_del(int sock, const char *brname);
+int linux_br_add_if(int sock, const char *brname, const char *ifname);
+int linux_br_del_if(int sock, const char *brname, const char *ifname);
+int linux_br_get(char *brname, const char *ifname);
+int linux_master_get(char *master_ifname, const char *ifname);
+
+#endif /* LINUX_IOCTL_H */
diff --git a/contrib/wpa/src/drivers/linux_wext.h b/contrib/wpa/src/drivers/linux_wext.h
new file mode 100644
index 000000000000..e7c7001e1cea
--- /dev/null
+++ b/contrib/wpa/src/drivers/linux_wext.h
@@ -0,0 +1,45 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <stdint.h>
+#include <net/if.h>
+typedef uint32_t __u32;
+typedef int32_t __s32;
+typedef uint16_t __u16;
+typedef int16_t __s16;
+typedef uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */
diff --git a/contrib/wpa/src/drivers/netlink.c b/contrib/wpa/src/drivers/netlink.c
new file mode 100644
index 000000000000..0e960f48c0ad
--- /dev/null
+++ b/contrib/wpa/src/drivers/netlink.c
@@ -0,0 +1,226 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2014, 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 "eloop.h"
+#include "priv_netlink.h"
+#include "netlink.h"
+
+
+struct netlink_data {
+ struct netlink_config *cfg;
+ int sock;
+};
+
+
+static void netlink_receive_link(struct netlink_data *netlink,
+ void (*cb)(void *ctx, struct ifinfomsg *ifi,
+ u8 *buf, size_t len),
+ struct nlmsghdr *h)
+{
+ if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
+ return;
+ cb(netlink->cfg->ctx, NLMSG_DATA(h),
+ (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+ NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
+}
+
+
+static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct netlink_data *netlink = eloop_ctx;
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, left)) {
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ netlink_receive_link(netlink, netlink->cfg->newlink_cb,
+ h);
+ break;
+ case RTM_DELLINK:
+ netlink_receive_link(netlink, netlink->cfg->dellink_cb,
+ h);
+ break;
+ }
+
+ h = NLMSG_NEXT(h, left);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
+ "netlink message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+struct netlink_data * netlink_init(struct netlink_config *cfg)
+{
+ struct netlink_data *netlink;
+ struct sockaddr_nl local;
+
+ netlink = os_zalloc(sizeof(*netlink));
+ if (netlink == NULL)
+ return NULL;
+
+ netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (netlink->sock < 0) {
+ wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
+ "socket: %s", strerror(errno));
+ netlink_deinit(netlink);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
+ {
+ wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
+ "socket: %s", strerror(errno));
+ netlink_deinit(netlink);
+ return NULL;
+ }
+
+ eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
+ NULL);
+
+ netlink->cfg = cfg;
+
+ return netlink;
+}
+
+
+void netlink_deinit(struct netlink_data *netlink)
+{
+ if (netlink == NULL)
+ return;
+ if (netlink->sock >= 0) {
+ eloop_unregister_read_sock(netlink->sock);
+ close(netlink->sock);
+ }
+ os_free(netlink->cfg);
+ os_free(netlink);
+}
+
+
+static const char * linkmode_str(int mode)
+{
+ switch (mode) {
+ case -1:
+ return "no change";
+ case 0:
+ return "kernel-control";
+ case 1:
+ return "userspace-control";
+ }
+ return "?";
+}
+
+
+static const char * operstate_str(int state)
+{
+ switch (state) {
+ case -1:
+ return "no change";
+ case IF_OPER_DORMANT:
+ return "IF_OPER_DORMANT";
+ case IF_OPER_UP:
+ return "IF_OPER_UP";
+ }
+ return "?";
+}
+
+
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
+ ifindex, linkmode, linkmode_str(linkmode),
+ operstate, operstate_str(operstate));
+
+ ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
+ "failed: %s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
diff --git a/contrib/wpa/src/drivers/netlink.h b/contrib/wpa/src/drivers/netlink.h
new file mode 100644
index 000000000000..3a7340e51534
--- /dev/null
+++ b/contrib/wpa/src/drivers/netlink.h
@@ -0,0 +1,28 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NETLINK_H
+#define NETLINK_H
+
+struct netlink_data;
+struct ifinfomsg;
+
+struct netlink_config {
+ void *ctx;
+ void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+ size_t len);
+ void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+ size_t len);
+};
+
+struct netlink_data * netlink_init(struct netlink_config *cfg);
+void netlink_deinit(struct netlink_data *netlink);
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+ int linkmode, int operstate);
+
+#endif /* NETLINK_H */
diff --git a/contrib/wpa/src/drivers/nl80211_copy.h b/contrib/wpa/src/drivers/nl80211_copy.h
index 6f09d1500960..f962c06e9818 100644
--- a/contrib/wpa/src/drivers/nl80211_copy.h
+++ b/contrib/wpa/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+#define NL80211_EDMG_BW_CONFIG_MIN 4
+#define NL80211_EDMG_BW_CONFIG_MAX 15
+#define NL80211_EDMG_CHANNELS_MIN 1
+#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
+
/**
* DOC: Station handling
*
@@ -178,18 +183,27 @@
*
* By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers
* can indicate they support offloading EAPOL handshakes for WPA/WPA2
- * preshared key authentication. In %NL80211_CMD_CONNECT the preshared
- * key should be specified using %NL80211_ATTR_PMK. Drivers supporting
- * this offload may reject the %NL80211_CMD_CONNECT when no preshared
- * key material is provided, for example when that driver does not
- * support setting the temporal keys through %CMD_NEW_KEY.
+ * preshared key authentication in station mode. In %NL80211_CMD_CONNECT
+ * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers
+ * supporting this offload may reject the %NL80211_CMD_CONNECT when no
+ * preshared key material is provided, for example when that driver does
+ * not support setting the temporal keys through %NL80211_CMD_NEW_KEY.
*
* Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
* set by drivers indicating offload support of the PTK/GTK EAPOL
- * handshakes during 802.1X authentication. In order to use the offload
- * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
- * attribute flag. Drivers supporting this offload may reject the
- * %NL80211_CMD_CONNECT when the attribute flag is not present.
+ * handshakes during 802.1X authentication in station mode. In order to
+ * use the offload the %NL80211_CMD_CONNECT should have
+ * %NL80211_ATTR_WANT_1X_4WAY_HS attribute flag. Drivers supporting this
+ * offload may reject the %NL80211_CMD_CONNECT when the attribute flag is
+ * not present.
+ *
+ * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK flag drivers
+ * can indicate they support offloading EAPOL handshakes for WPA/WPA2
+ * preshared key authentication in AP mode. In %NL80211_CMD_START_AP
+ * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers
+ * supporting this offload may reject the %NL80211_CMD_START_AP when no
+ * preshared key material is provided, for example when that driver does
+ * not support setting the temporal keys through %NL80211_CMD_NEW_KEY.
*
* For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
* using %NL80211_CMD_SET_PMK. For offloaded FT support also
@@ -235,6 +249,58 @@
*/
/**
+ * DOC: SAE authentication offload
+ *
+ * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
+ * support offloading SAE authentication for WPA3-Personal networks in station
+ * mode. Similarly @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP flag can be set by
+ * drivers indicating the offload support in AP mode.
+ *
+ * The password for SAE should be specified using %NL80211_ATTR_SAE_PASSWORD in
+ * %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP for station and AP mode
+ * respectively.
+ */
+
+/**
+ * DOC: VLAN offload support for setting group keys and binding STAs to VLANs
+ *
+ * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they
+ * support offloading VLAN functionality in a manner where the driver exposes a
+ * single netdev that uses VLAN tagged frames and separate VLAN-specific netdevs
+ * can then be added using RTM_NEWLINK/IFLA_VLAN_ID similarly to the Ethernet
+ * case. Frames received from stations that are not assigned to any VLAN are
+ * delivered on the main netdev and frames to such stations can be sent through
+ * that main netdev.
+ *
+ * %NL80211_CMD_NEW_KEY (for group keys), %NL80211_CMD_NEW_STATION, and
+ * %NL80211_CMD_SET_STATION will optionally specify vlan_id using
+ * %NL80211_ATTR_VLAN_ID.
+ */
+
+/**
+ * DOC: TID configuration
+ *
+ * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG
+ * attribute given in wiphy capabilities.
+ *
+ * The necessary configuration parameters are mentioned in
+ * &enum nl80211_tid_config_attr and it will be passed to the
+ * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG.
+ *
+ * If the configuration needs to be applied for specific peer then the MAC
+ * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
+ * configuration will be applied for all the connected peers in the vif except
+ * any peers that have peer specific configuration for the TID by default; if
+ * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
+ * will be overwritten.
+ *
+ * All this configuration is valid only for STA's current connection
+ * i.e. the configuration will be reset to default when the STA connects back
+ * after disconnection/roaming, and this configuration will be cleared when
+ * the interface goes down.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -243,13 +309,14 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
- * attributes determining the channel width; this is used for setting
- * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
- * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
- * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
- * instead, the support here is for backward compatibility only.
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the
+ * channel width; this is used for setting monitor mode channel),
+ * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG,
+ * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or
+ * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel,
+ * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward
+ * compatibility only.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -298,7 +365,8 @@
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the
+ * attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -308,7 +376,7 @@
* @NL80211_CMD_SET_STATION: Set station attributes for station identified by
* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
- * the interface identified by %NL80211_ATTR_IFINDEX.
+ * interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all stations, on the interface identified
* by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
@@ -328,7 +396,7 @@
* @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
* %NL80211_ATTR_MAC.
* @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
- * the interface identified by %NL80211_ATTR_IFINDEX.
+ * interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all mesh paths, on the interface identified
* by %NL80211_ATTR_IFINDEX.
@@ -483,11 +551,12 @@
* interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
* BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
* the SSID (mainly for association, but is included in authentication
- * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
- * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
- * is used to specify the authentication type. %NL80211_ATTR_IE is used to
- * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
- * to be added to the frame.
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ +
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the
+ * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the
+ * authentication type. %NL80211_ATTR_IE is used to define IEs
+ * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added
+ * to the frame.
* When used as an event, this reports reception of an Authentication
* frame in station and IBSS modes when the local MLME processed the
* frame, i.e., it was for the local STA and was received in correct
@@ -542,8 +611,9 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
- * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE,
+ * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
* %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
@@ -557,6 +627,14 @@
* set of BSSID,frequency parameters is used (i.e., either the enforcing
* %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
* %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
+ * Driver shall not modify the IEs specified through %NL80211_ATTR_IE if
+ * %NL80211_ATTR_MAC is included. However, if %NL80211_ATTR_MAC_HINT is
+ * included, these IEs through %NL80211_ATTR_IE are specified by the user
+ * space based on the best possible BSS selected. Thus, if the driver ends
+ * up selecting a different BSS, it can modify these IEs accordingly (e.g.
+ * userspace asks the driver to perform PMKSA caching with BSS1 and the
+ * driver ends up selecting BSS2 with different PMKSA cache entry; RSNIE
+ * has to get updated with the apt PMKID).
* %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within
* the ESS in case the device is already associated and an association with
* a different BSS is desired.
@@ -573,14 +651,13 @@
* authentication/association or not receiving a response from the AP.
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
* well to remain backwards compatible.
- * When establishing a security association, drivers that support 4 way
- * handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
- * the 4 way handshake is completed successfully.
* @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
- * When a security association was established with the new AP (e.g. if
- * the FT protocol was used for roaming or the driver completed the 4 way
- * handshake), this event should be followed by an
+ * When a security association was established on an 802.1X network using
+ * fast transition, this event should be followed by an
* %NL80211_CMD_PORT_AUTHORIZED event.
+ * Following a %NL80211_CMD_ROAM event userspace can issue
+ * %NL80211_CMD_GET_SCAN in order to obtain the scan information for the
+ * new BSS the card/driver roamed to.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -626,6 +703,10 @@
* four bytes for vendor frames including the OUI. The registration
* cannot be dropped, but is removed automatically when the netlink
* socket is closed. Multiple registrations can be made.
+ * The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if
+ * %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which
+ * case the registration can also be modified to include/exclude the
+ * flag, rather than requiring unregistration to change it.
* @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
* backward compatibility
* @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
@@ -648,7 +729,9 @@
* is used during CSA period.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
- * time if it is known that it is no longer necessary.
+ * time if it is known that it is no longer necessary. This command is
+ * also sent as an event whenever the driver has completed the off-channel
+ * wait time.
* @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
* @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
@@ -677,7 +760,8 @@
* of any other interfaces, and other interfaces will again take
* precedence when they are used.
*
- * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface
+ * (no longer supported).
*
* @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
* multicast to unicast conversion. When enabled, all multicast packets
@@ -723,7 +807,7 @@
* various triggers. These triggers can be configured through this
* command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
* more background information, see
- * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ * https://wireless.wiki.kernel.org/en/users/Documentation/WoWLAN.
* The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
* from the driver reporting the wakeup reason. In this case, the
* @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
@@ -863,7 +947,7 @@
* @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
*
* @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
- * the new channel information (Channel Switch Announcement - CSA)
+ * new channel information (Channel Switch Announcement - CSA)
* in the beacon for some time (as defined in the
* %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
* new channel. Userspace provides the new channel information (using
@@ -987,13 +1071,11 @@
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
* configured PMK for the authenticator address identified by
* %NL80211_ATTR_MAC.
- * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
- * handshake was completed successfully by the driver. The BSSID is
- * specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
- * offload should send this event after indicating 802.11 association with
- * %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
- * %NL80211_CMD_DISCONNECT should be indicated instead.
- *
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was
+ * completed successfully. Drivers that support 4 way handshake offload
+ * should send this event after indicating 802.1X FT assocation with
+ * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT
+ * should be indicated instead.
* @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
* and RX notification. This command is used both as a request to transmit
* a control port frame and as a notification that a control port frame
@@ -1042,7 +1124,7 @@
* randomization may be enabled and configured by specifying the
* %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes.
* If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute.
- * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in
+ * A u64 cookie for further %NL80211_ATTR_COOKIE use is returned in
* the netlink extended ack message.
*
* To cancel a measurement, close the socket that requested it.
@@ -1085,6 +1167,24 @@
* peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
* content. The frame is ethernet data.
*
+ * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
+ * is passed using %NL80211_ATTR_TID_CONFIG attribute.
+ *
+ * @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon
+ * frame. This event is used to indicate that a received Beacon frame was
+ * dropped because it did not include a valid MME MIC while beacon
+ * protection was enabled (BIGTK configured in station mode).
+ *
+ * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control
+ * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME.
+ * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME
+ * includes the contents of the frame. %NL80211_ATTR_ACK flag is included
+ * if the recipient acknowledged the frame.
+ *
+ * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is
+ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
+ * specify the wiphy index to be applied to.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1309,6 +1409,14 @@ enum nl80211_commands {
NL80211_CMD_PROBE_MESH_LINK,
+ NL80211_CMD_SET_TID_CONFIG,
+
+ NL80211_CMD_UNPROT_BEACON,
+
+ NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
+
+ NL80211_CMD_SET_SAR_SPECS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1354,7 +1462,8 @@ enum nl80211_commands {
* of &enum nl80211_chan_width, describing the channel width. See the
* documentation of the enum for more information.
* @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
- * channel, used for anything but 20 MHz bandwidth
+ * channel, used for anything but 20 MHz bandwidth. In S1G this is the
+ * operating channel center frequency.
* @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
* channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
@@ -1419,7 +1528,7 @@ enum nl80211_commands {
* rates as defined by IEEE 802.11 7.3.2.2 but without the length
* restriction (at most %NL80211_MAX_SUPP_RATES).
* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
- * to, or the AP interface the station was originally added to to.
+ * to, or the AP interface the station was originally added to.
* @NL80211_ATTR_STA_INFO: information about a station, part of station info
* given for %NL80211_CMD_GET_STATION, nested attribute containing
* info as possible, see &enum nl80211_sta_info.
@@ -1564,7 +1673,8 @@ enum nl80211_commands {
* flag is included, then control port frames are sent over NL80211 instead
* using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
* to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
- * flag.
+ * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth
+ * frames are not forwared over the control port.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -1650,8 +1760,9 @@ enum nl80211_commands {
* specify just a single bitrate, which is to be used for the beacon.
* The driver must also specify support for this with the extended
* features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
- * NL80211_EXT_FEATURE_BEACON_RATE_HT and
- * NL80211_EXT_FEATURE_BEACON_RATE_VHT.
+ * NL80211_EXT_FEATURE_BEACON_RATE_HT,
+ * NL80211_EXT_FEATURE_BEACON_RATE_VHT and
+ * NL80211_EXT_FEATURE_BEACON_RATE_HE.
*
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
@@ -1855,8 +1966,15 @@ enum nl80211_commands {
* @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
* probe-response frame. The DA field in the 802.11 header is zero-ed out,
* to be filled by the FW.
- * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
- * this feature. Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
* @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
* ATTR_HT_CAPABILITY to which attention should be paid.
* Currently, only mac80211 NICs support this feature.
@@ -1977,13 +2095,14 @@ enum nl80211_commands {
* until the channel switch event.
* @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
* must be blocked on the current channel (before the channel switch
- * operation).
+ * operation). Also included in the channel switch started event if quiet
+ * was requested by the AP.
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch.
- * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel
- * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
- * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel
- * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).
+ * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel
+ * switch or color change counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CNTDWN_OFFS_PRESP: An array of offsets (u16) to the channel
+ * switch or color change counters in the probe response (%NL80211_ATTR_PROBE_RESP).
*
* @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
* As specified in the &enum nl80211_rxmgmt_flags.
@@ -1991,7 +2110,7 @@ enum nl80211_commands {
* @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
*
* @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
- * supported operating classes.
+ * operating classes.
*
* @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
* controls DFS operation in IBSS mode. If the flag is included in
@@ -2269,10 +2388,11 @@ enum nl80211_commands {
*
* @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
* %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
- * For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
- * handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
- * used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
- * specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
+ * For %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP it is used to provide
+ * PSK for offloading 4-way handshake for WPA/WPA2-PSK networks. For 802.1X
+ * authentication it is used with %NL80211_CMD_SET_PMK. For offloaded FT
+ * support this attribute specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME
+ * is included as well.
*
* @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
* indicate that it supports multiple active scheduled scan requests.
@@ -2302,7 +2422,7 @@ enum nl80211_commands {
* nl80211_txq_stats)
* @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
* The smaller of this and the memory limit is enforced.
- * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
+ * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory limit (in bytes) for the
* TXQ queues for this phy. The smaller of this and the packet limit is
* enforced.
* @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
@@ -2341,6 +2461,105 @@ enum nl80211_commands {
* should be picking up the lowest tx power, either tx power per-interface
* or per-station.
*
+ * @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It
+ * is used with %NL80211_CMD_CONNECT to provide password for offloading
+ * SAE authentication for WPA3-Personal networks.
+ *
+ * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support.
+ *
+ * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
+ * functionality.
+ *
+ * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
+ * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations. (u8 attribute)
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ *
+ * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
+ * (u16).
+ *
+ * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings.
+ *
+ * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry
+ * using attributes from &enum nl80211_iftype_akm_attributes. This
+ * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating
+ * supported AKM suites capability per interface. AKMs advertised in
+ * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
+ * advertised for a specific interface type.
+ *
+ * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
+ * nested attribute with &enum nl80211_tid_config_attr sub-attributes;
+ * on output (in wiphy attributes) it contains only the feature sub-
+ * attributes.
+ *
+ * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control
+ * port in order to forward/receive them as ordinary data frames.
+ *
+ * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32,
+ * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value).
+ * An optional parameter configured through %NL80211_CMD_SET_PMKSA.
+ * Drivers that trigger roaming need to know the lifetime of the
+ * configured PMKSA for triggering the full vs. PMKSA caching based
+ * authentication. This timeout helps authentication methods like SAE,
+ * where PMK gets updated only by going through a full (new SAE)
+ * authentication instead of getting updated during an association for EAP
+ * authentication. No new full authentication within the PMK expiry shall
+ * result in a disassociation at the end of the lifetime.
+ *
+ * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in
+ * terms of percentage of %NL80211_ATTR_PMK_LIFETIME
+ * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional
+ * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the
+ * driver to trigger a full authentication roam (without PMKSA caching)
+ * after the reauthentication threshold time, but before the PMK lifetime
+ * has expired.
+ *
+ * Authentication methods like SAE need to be able to generate a new PMKSA
+ * entry without having to force a disconnection after the PMK timeout. If
+ * no roaming occurs between the reauth threshold and PMK expiration,
+ * disassociation is still forced.
+ * @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
+ * %NL80211_CMD_REGISTER_FRAME command, see the description there.
+ * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated
+ * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with
+ * an %NL80211_ATTR_WIPHY_FREQ_OFFSET.
+ * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the
+ * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1.
+ * @NL80211_ATTR_SCAN_FREQ_KHZ: nested attribute with KHz frequencies
+ *
+ * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
+ * association request when used with NL80211_CMD_NEW_STATION).
+ *
+ * @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS
+ * discovery. It is a nested attribute, see
+ * &enum nl80211_fils_discovery_attributes.
+ *
+ * @NL80211_ATTR_UNSOL_BCAST_PROBE_RESP: Optional parameter to configure
+ * unsolicited broadcast probe response. It is a nested attribute, see
+ * &enum nl80211_unsol_bcast_probe_resp_attributes.
+ *
+ * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ * @NL80211_ATTR_S1G_CAPABILITY_MASK: S1G Capability Information element
+ * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
+ * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE
+ * derivation in WPA3-Personal networks which are using SAE authentication.
+ * This is a u8 attribute that encapsulates one of the values from
+ * &enum nl80211_sae_pwe_mechanism.
+ *
+ * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when
+ * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields
+ * of %nl80211_sar_attrs which specifies the sar type and related
+ * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs.
+ *
+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
+ * disassoc events to indicate that an immediate reconnect to the AP
+ * is desired.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2647,8 +2866,8 @@ enum nl80211_attrs {
NL80211_ATTR_CH_SWITCH_COUNT,
NL80211_ATTR_CH_SWITCH_BLOCK_TX,
NL80211_ATTR_CSA_IES,
- NL80211_ATTR_CSA_C_OFF_BEACON,
- NL80211_ATTR_CSA_C_OFF_PRESP,
+ NL80211_ATTR_CNTDWN_OFFS_BEACON,
+ NL80211_ATTR_CNTDWN_OFFS_PRESP,
NL80211_ATTR_RXMGMT_FLAGS,
@@ -2794,6 +3013,50 @@ enum nl80211_attrs {
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
+ NL80211_ATTR_SAE_PASSWORD,
+
+ NL80211_ATTR_TWT_RESPONDER,
+
+ NL80211_ATTR_HE_OBSS_PD,
+
+ NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+
+ NL80211_ATTR_VLAN_ID,
+
+ NL80211_ATTR_HE_BSS_COLOR,
+
+ NL80211_ATTR_IFTYPE_AKM_SUITES,
+
+ NL80211_ATTR_TID_CONFIG,
+
+ NL80211_ATTR_CONTROL_PORT_NO_PREAUTH,
+
+ NL80211_ATTR_PMK_LIFETIME,
+ NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+
+ NL80211_ATTR_RECEIVE_MULTICAST,
+ NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ NL80211_ATTR_CENTER_FREQ1_OFFSET,
+ NL80211_ATTR_SCAN_FREQ_KHZ,
+
+ NL80211_ATTR_HE_6GHZ_CAPABILITY,
+
+ NL80211_ATTR_FILS_DISCOVERY,
+
+ NL80211_ATTR_UNSOL_BCAST_PROBE_RESP,
+
+ NL80211_ATTR_S1G_CAPABILITY,
+ NL80211_ATTR_S1G_CAPABILITY_MASK,
+
+ NL80211_ATTR_SAE_PWE,
+
+ NL80211_ATTR_RECONNECT_REQUESTED,
+
+ NL80211_ATTR_SAR_SPEC,
+
+ NL80211_ATTR_DISABLE_HE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2806,6 +3069,8 @@ enum nl80211_attrs {
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
+#define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON
+#define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -2844,7 +3109,7 @@ enum nl80211_attrs {
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
#define NL80211_HE_MIN_CAPABILITY_LEN 16
-#define NL80211_HE_MAX_CAPABILITY_LEN 51
+#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -2984,6 +3249,18 @@ enum nl80211_he_gi {
};
/**
+ * enum nl80211_he_ltf - HE long training field
+ * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec
+ * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec
+ * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec
+ */
+enum nl80211_he_ltf {
+ NL80211_RATE_INFO_HE_1XLTF,
+ NL80211_RATE_INFO_HE_2XLTF,
+ NL80211_RATE_INFO_HE_4XLTF,
+};
+
+/**
* enum nl80211_he_ru_alloc - HE RU allocation values
* @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
* @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
@@ -3175,6 +3452,10 @@ enum nl80211_sta_bss_param {
* sent to the station (u64, usec)
* @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
+ * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
+ * of STA's association
+ * @NL80211_STA_INFO_CONNECTED_TO_AS: set to true if STA has a path to a
+ * authentication server (u8, 0 or 1)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3221,6 +3502,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
+ NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
+ NL80211_STA_INFO_CONNECTED_TO_AS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3369,6 +3652,8 @@ enum nl80211_mpath_info {
* defined in HE capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
* defined
+ * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
+ * given for all 6 GHz band channels
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
@@ -3379,6 +3664,7 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+ NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -3402,6 +3688,12 @@ enum nl80211_band_iftype_attr {
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
* attributes from &enum nl80211_band_iftype_attr
+ * @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
+ * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -3419,6 +3711,9 @@ enum nl80211_band_attr {
NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA,
+ NL80211_BAND_ATTR_EDMG_CHANNELS,
+ NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -3501,6 +3796,19 @@ enum nl80211_wmm_rule {
* @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
* This is a nested attribute that contains the wmm limitation per AC.
* (see &enum nl80211_wmm_rule)
+ * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
+ * in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz
+ * @NL80211_FREQUENCY_ATTR_1MHZ: 1 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_2MHZ: 2 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_4MHZ: 4 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_8MHZ: 8 MHz operation is allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
+ * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3530,6 +3838,13 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
+ NL80211_FREQUENCY_ATTR_NO_HE,
+ NL80211_FREQUENCY_ATTR_OFFSET,
+ NL80211_FREQUENCY_ATTR_1MHZ,
+ NL80211_FREQUENCY_ATTR_2MHZ,
+ NL80211_FREQUENCY_ATTR_4MHZ,
+ NL80211_FREQUENCY_ATTR_8MHZ,
+ NL80211_FREQUENCY_ATTR_16MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3727,6 +4042,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
+ * @NL80211_RRF_NO_HE: HE operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -3744,6 +4060,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_HT40PLUS = 1<<14,
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
+ NL80211_RRF_NO_HE = 1<<17,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -3817,8 +4134,11 @@ enum nl80211_user_reg_hint_type {
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent
+ * receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
+ * @NL80211_SURVEY_INFO_FREQUENCY_OFFSET: center frequency offset in KHz
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
*/
enum nl80211_survey_info {
@@ -3833,6 +4153,8 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
+ NL80211_SURVEY_INFO_TIME_BSS_RX,
+ NL80211_SURVEY_INFO_FREQUENCY_OFFSET,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4018,6 +4340,16 @@ enum nl80211_mesh_power_mode {
* field. If left unset then the mesh formation field will only
* advertise such if there is an active root mesh path.
*
+ * @NL80211_MESHCONF_NOLEARN: Try to avoid multi-hop path discovery (e.g.
+ * PREQ/PREP for HWMP) if the destination is a direct neighbor. Note that
+ * this might not be the optimal decision as a multi-hop route might be
+ * better. So if using this setting you will likely also want to disable
+ * dot11MeshForwarding and use another mesh routing protocol on top.
+ *
+ * @NL80211_MESHCONF_CONNECTED_TO_AS: If set to true then this mesh STA
+ * will advertise that it is connected to a authentication server
+ * in the mesh formation field.
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -4051,6 +4383,8 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_AWAKE_WINDOW,
NL80211_MESHCONF_PLINK_TIMEOUT,
NL80211_MESHCONF_CONNECTED_TO_GATE,
+ NL80211_MESHCONF_NOLEARN,
+ NL80211_MESHCONF_CONNECTED_TO_AS,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -4219,6 +4553,11 @@ enum nl80211_key_mode {
* attribute must be provided as well
* @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
* @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_1: 1 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_2: 2 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
@@ -4229,6 +4568,11 @@ enum nl80211_chan_width {
NL80211_CHAN_WIDTH_160,
NL80211_CHAN_WIDTH_5,
NL80211_CHAN_WIDTH_10,
+ NL80211_CHAN_WIDTH_1,
+ NL80211_CHAN_WIDTH_2,
+ NL80211_CHAN_WIDTH_4,
+ NL80211_CHAN_WIDTH_8,
+ NL80211_CHAN_WIDTH_16,
};
/**
@@ -4239,11 +4583,15 @@ enum nl80211_chan_width {
* @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible
* @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide
* @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_1: control channel is 1 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_2: control channel is 2 MHz wide
*/
enum nl80211_bss_scan_width {
NL80211_BSS_CHAN_WIDTH_20,
NL80211_BSS_CHAN_WIDTH_10,
NL80211_BSS_CHAN_WIDTH_5,
+ NL80211_BSS_CHAN_WIDTH_1,
+ NL80211_BSS_CHAN_WIDTH_2,
};
/**
@@ -4295,6 +4643,7 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
* Contains a nested array of signal strength attributes (u8, dBm),
* using the nesting index as the antenna number.
+ * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -4319,6 +4668,7 @@ enum nl80211_bss {
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
NL80211_BSS_CHAIN_SIGNAL,
+ NL80211_BSS_FREQUENCY_OFFSET,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -4406,6 +4756,7 @@ enum nl80211_mfp {
enum nl80211_wpa_versions {
NL80211_WPA_VERSION_1 = 1 << 0,
NL80211_WPA_VERSION_2 = 1 << 1,
+ NL80211_WPA_VERSION_3 = 1 << 2,
};
/**
@@ -4446,6 +4797,7 @@ enum nl80211_key_default_types {
* See &enum nl80211_key_default_types.
* @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
* Defaults to @NL80211_KEY_RX_TX.
+ * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key
*
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
@@ -4461,6 +4813,7 @@ enum nl80211_key_attributes {
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE,
+ NL80211_KEY_DEFAULT_BEACON,
/* keep last */
__NL80211_KEY_AFTER_LAST,
@@ -4479,6 +4832,10 @@ enum nl80211_key_attributes {
* @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
* see &struct nl80211_txrate_vht
* @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi
+ * @NL80211_TXRATE_HE: HE rates allowed for TX rate selection,
+ * see &struct nl80211_txrate_he
+ * @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us.
+ * @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF.
* @__NL80211_TXRATE_AFTER_LAST: internal
* @NL80211_TXRATE_MAX: highest TX rate attribute
*/
@@ -4488,6 +4845,9 @@ enum nl80211_tx_rate_attributes {
NL80211_TXRATE_HT,
NL80211_TXRATE_VHT,
NL80211_TXRATE_GI,
+ NL80211_TXRATE_HE,
+ NL80211_TXRATE_HE_GI,
+ NL80211_TXRATE_HE_LTF,
/* keep last */
__NL80211_TXRATE_AFTER_LAST,
@@ -4505,6 +4865,15 @@ struct nl80211_txrate_vht {
__u16 mcs[NL80211_VHT_NSS_MAX];
};
+#define NL80211_HE_NSS_MAX 8
+/**
+ * struct nl80211_txrate_he - HE MCS/NSS txrate bitmap
+ * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.)
+ */
+struct nl80211_txrate_he {
+ __u16 mcs[NL80211_HE_NSS_MAX];
+};
+
enum nl80211_txrate_gi {
NL80211_TXRATE_DEFAULT_GI,
NL80211_TXRATE_FORCE_SGI,
@@ -4516,6 +4885,8 @@ enum nl80211_txrate_gi {
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
+ * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
+ * @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4523,6 +4894,8 @@ enum nl80211_band {
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
+ NL80211_BAND_S1GHZ,
NUM_NL80211_BANDS,
};
@@ -4615,6 +4988,92 @@ enum nl80211_tx_power_setting {
};
/**
+ * enum nl80211_tid_config - TID config state
+ * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID
+ * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID
+ */
+enum nl80211_tid_config {
+ NL80211_TID_CONFIG_ENABLE,
+ NL80211_TID_CONFIG_DISABLE,
+};
+
+/* enum nl80211_tx_rate_setting - TX rate configuration type
+ * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate
+ * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter
+ * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter
+ */
+enum nl80211_tx_rate_setting {
+ NL80211_TX_RATE_AUTOMATIC,
+ NL80211_TX_RATE_LIMITED,
+ NL80211_TX_RATE_FIXED,
+};
+
+/* enum nl80211_tid_config_attr - TID specific configuration.
+ * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
+ * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
+ * for per-vif configuration; doesn't list the ones that are generic
+ * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
+ * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
+ * per peer instead.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates
+ * that the new configuration overrides all previous peer
+ * configurations, otherwise previous peer specific configurations
+ * should be left untouched.
+ * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
+ * Its type is u16.
+ * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
+ * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config.
+ * Its type is u8.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable MPDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
+ * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
+ * the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_AMSDU_CTRL: Enable/Disable MSDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE: This attribute will be useful
+ * to notfiy the driver that what type of txrate should be used
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. using
+ * the values form &nl80211_tx_rate_setting.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE: Data frame TX rate mask should be applied
+ * with the parameters passed through %NL80211_ATTR_TX_RATES.
+ * configuration is applied to the data frame for the tid to that connected
+ * station.
+ */
+enum nl80211_tid_config_attr {
+ __NL80211_TID_CONFIG_ATTR_INVALID,
+ NL80211_TID_CONFIG_ATTR_PAD,
+ NL80211_TID_CONFIG_ATTR_VIF_SUPP,
+ NL80211_TID_CONFIG_ATTR_PEER_SUPP,
+ NL80211_TID_CONFIG_ATTR_OVERRIDE,
+ NL80211_TID_CONFIG_ATTR_TIDS,
+ NL80211_TID_CONFIG_ATTR_NOACK,
+ NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+ NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+ NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+ NL80211_TID_CONFIG_ATTR_AMSDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE,
+ NL80211_TID_CONFIG_ATTR_TX_RATE,
+
+ /* keep last */
+ __NL80211_TID_CONFIG_ATTR_AFTER_LAST,
+ NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_packet_pattern_attr - packet pattern attribute
* @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
* @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
@@ -5085,6 +5544,8 @@ enum plink_actions {
#define NL80211_KCK_LEN 16
#define NL80211_KEK_LEN 16
+#define NL80211_KCK_EXT_LEN 24
+#define NL80211_KEK_EXT_LEN 32
#define NL80211_REPLAY_CTR_LEN 8
/**
@@ -5093,6 +5554,7 @@ enum plink_actions {
* @NL80211_REKEY_DATA_KEK: key encryption key (binary)
* @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
* @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NL80211_REKEY_DATA_AKM: AKM data (OUI, suite type)
* @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
* @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
*/
@@ -5101,6 +5563,7 @@ enum nl80211_rekey_data {
NL80211_REKEY_DATA_KEK,
NL80211_REKEY_DATA_KCK,
NL80211_REKEY_DATA_REPLAY_CTR,
+ NL80211_REKEY_DATA_AKM,
/* keep last */
NUM_NL80211_REKEY_DATA,
@@ -5314,14 +5777,14 @@ enum nl80211_feature_flags {
NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
- NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
};
/**
* enum nl80211_ext_feature_index - bit index of extended features.
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
* @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
- * can request to use RRM (see %NL80211_ATTR_USE_RRM) with
+ * request to use RRM (see %NL80211_ATTR_USE_RRM) with
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
* the ASSOC_REQ_USE_RRM flag in the association request even if
* NL80211_FEATURE_QUIET is not advertized.
@@ -5422,6 +5885,71 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
*
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
+ * station mode (SAE password is passed as part of the connect command).
+ *
+ * @NL80211_EXT_FEATURE_VLAN_OFFLOAD: The driver supports a single netdev
+ * with VLAN tagged frames and separate VLAN-specific netdevs added using
+ * vconfig similarly to the Ethernet case.
+ *
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ * feature, which prevents bufferbloat by using the expected transmission
+ * time to limit the amount of data buffered in the hardware.
+ *
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
+ * and can receive key configuration for BIGTK using key indexes 6 and 7.
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon
+ * protection as a client only and cannot transmit protected beacons.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
+ * forwarding of preauth frames over the control port. They are then
+ * handled as ordinary data frames.
+ *
+ * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames
+ *
+ * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
+ * in IBSS mode, essentially by dropping their state.
+ *
+ * @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
+ * are possible for multicast frames and those will be reported properly.
+ *
+ * @NL80211_EXT_FEATURE_SCAN_FREQ_KHZ: This driver supports receiving and
+ * reporting scan request with %NL80211_ATTR_SCAN_FREQ_KHZ. In order to
+ * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be
+ * included in the scan request.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver
+ * can report tx status for control port over nl80211 tx operations.
+ *
+ * @NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION: Driver supports Operating
+ * Channel Validation (OCV) when using driver's SME for RSNA handshakes.
+ *
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK: Device wants to do 4-way
+ * handshake with PSK in AP mode (PSK is passed as part of the start AP
+ * command).
+ *
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP: Device wants to do SAE authentication
+ * in AP mode (SAE password is passed as part of the start AP command).
+ *
+ * @NL80211_EXT_FEATURE_FILS_DISCOVERY: Driver/device supports FILS discovery
+ * frames transmission
+ *
+ * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
+ * unsolicited broadcast probe response transmission
+ *
+ * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate
+ * configuration (AP/mesh) with HE rates.
+ *
+ * @NL80211_EXT_FEATURE_SECURE_LTF: Device supports secure LTF measurement
+ * exchange protocol.
+ *
+ * @NL80211_EXT_FEATURE_SECURE_RTT: Device supports secure RTT measurement
+ * exchange protocol.
+ *
+ * @NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE: Device supports management
+ * frame protection for all management frames exchanged during the
+ * negotiation and range measurement procedure.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5466,6 +5994,26 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD,
+ NL80211_EXT_FEATURE_AQL,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION,
+ NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
+ NL80211_EXT_FEATURE_PROTECTED_TWT,
+ NL80211_EXT_FEATURE_DEL_IBSS_STA,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
+ NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS,
+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE,
+ NL80211_EXT_FEATURE_SECURE_LTF,
+ NL80211_EXT_FEATURE_SECURE_RTT,
+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -5577,6 +6125,11 @@ enum nl80211_timeout_reason {
* @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
* only have supported rates and no additional capabilities (unless
* added by userspace explicitly.)
+ * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
+ * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
+ * %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
+ * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by
+ * 2.4/5 GHz APs
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
@@ -5592,6 +6145,8 @@ enum nl80211_scan_flags {
NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
+ NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13,
+ NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14,
};
/**
@@ -5679,7 +6234,7 @@ enum nl80211_dfs_state {
};
/**
- * enum enum nl80211_protocol_features - nl80211 protocol features
+ * enum nl80211_protocol_features - nl80211 protocol features
* @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
* wiphy dumps (if requested by the application with the attribute
* %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
@@ -5756,11 +6311,13 @@ struct nl80211_vendor_cmd_info {
* @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
* @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
* @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
+ * @NL80211_TDLS_PEER_HE: TDLS peer is HE capable.
*/
enum nl80211_tdls_peer_capability {
NL80211_TDLS_PEER_HT = 1<<0,
NL80211_TDLS_PEER_VHT = 1<<1,
NL80211_TDLS_PEER_WMM = 1<<2,
+ NL80211_TDLS_PEER_HE = 1<<3,
};
/**
@@ -6088,12 +6645,14 @@ enum nl80211_ftm_responder_stats {
* @NL80211_PREAMBLE_HT: HT preamble
* @NL80211_PREAMBLE_VHT: VHT preamble
* @NL80211_PREAMBLE_DMG: DMG preamble
+ * @NL80211_PREAMBLE_HE: HE preamble
*/
enum nl80211_preamble {
NL80211_PREAMBLE_LEGACY,
NL80211_PREAMBLE_HT,
NL80211_PREAMBLE_VHT,
NL80211_PREAMBLE_DMG,
+ NL80211_PREAMBLE_HE,
};
/**
@@ -6286,6 +6845,10 @@ enum nl80211_peer_measurement_attrs {
* is valid)
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating
* the maximum FTMs per burst (if not present anything is valid)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if
+ * trigger based ranging measurement is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating
+ * if non trigger based ranging measurement is supported
*
* @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
@@ -6301,6 +6864,8 @@ enum nl80211_peer_measurement_ftm_capa {
NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED,
/* keep last */
NUM_NL80211_PMSR_FTM_CAPA_ATTR,
@@ -6330,6 +6895,23 @@ enum nl80211_peer_measurement_ftm_capa {
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
* (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging
+ * measurement (flag).
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based
+ * ranging measurement (flag)
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
+ * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6346,6 +6928,9 @@ enum nl80211_peer_measurement_ftm_req {
NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+ NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
+ NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -6464,4 +7049,254 @@ enum nl80211_peer_measurement_ftm_resp {
NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
};
+/**
+ * enum nl80211_obss_pd_attributes - OBSS packet detection attributes
+ * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET: the non-SRG OBSS PD maximum
+ * tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP: bitmap that indicates the BSS color
+ * values used by members of the SRG.
+ * @NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP: bitmap that indicates the partial
+ * BSSID values used by members of the SRG.
+ * @NL80211_HE_OBSS_PD_ATTR_SR_CTRL: The SR Control field of SRP element.
+ *
+ * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
+ * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
+ */
+enum nl80211_obss_pd_attributes {
+ __NL80211_HE_OBSS_PD_ATTR_INVALID,
+
+ NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
+ NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
+ NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
+
+ /* keep last */
+ __NL80211_HE_OBSS_PD_ATTR_LAST,
+ NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_bss_color_attributes - BSS Color attributes
+ * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color.
+ * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled.
+ * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used..
+ *
+ * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal
+ * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute.
+ */
+enum nl80211_bss_color_attributes {
+ __NL80211_HE_BSS_COLOR_ATTR_INVALID,
+
+ NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ NL80211_HE_BSS_COLOR_ATTR_DISABLED,
+ NL80211_HE_BSS_COLOR_ATTR_PARTIAL,
+
+ /* keep last */
+ __NL80211_HE_BSS_COLOR_ATTR_LAST,
+ NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_iftype_akm_attributes - interface type AKM attributes
+ * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid
+ *
+ * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag
+ * attribute for each interface type that supports AKM suites specified in
+ * %NL80211_IFTYPE_AKM_ATTR_SUITES
+ * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported
+ * AKM suites for the specified interface types.
+ *
+ * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal
+ * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute.
+ */
+enum nl80211_iftype_akm_attributes {
+ __NL80211_IFTYPE_AKM_ATTR_INVALID,
+
+ NL80211_IFTYPE_AKM_ATTR_IFTYPES,
+ NL80211_IFTYPE_AKM_ATTR_SUITES,
+
+ /* keep last */
+ __NL80211_IFTYPE_AKM_ATTR_LAST,
+ NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_fils_discovery_attributes - FILS discovery configuration
+ * from IEEE Std 802.11ai-2016, Annex C.3 MIB detail.
+ *
+ * @__NL80211_FILS_DISCOVERY_ATTR_INVALID: Invalid
+ *
+ * @NL80211_FILS_DISCOVERY_ATTR_INT_MIN: Minimum packet interval (u32, TU).
+ * Allowed range: 0..10000 (TU = Time Unit)
+ * @NL80211_FILS_DISCOVERY_ATTR_INT_MAX: Maximum packet interval (u32, TU).
+ * Allowed range: 0..10000 (TU = Time Unit)
+ * @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action
+ * frame including the headers.
+ *
+ * @__NL80211_FILS_DISCOVERY_ATTR_LAST: Internal
+ * @NL80211_FILS_DISCOVERY_ATTR_MAX: highest attribute
+ */
+enum nl80211_fils_discovery_attributes {
+ __NL80211_FILS_DISCOVERY_ATTR_INVALID,
+
+ NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ NL80211_FILS_DISCOVERY_ATTR_TMPL,
+
+ /* keep last */
+ __NL80211_FILS_DISCOVERY_ATTR_LAST,
+ NL80211_FILS_DISCOVERY_ATTR_MAX = __NL80211_FILS_DISCOVERY_ATTR_LAST - 1
+};
+
+/*
+ * FILS discovery template minimum length with action frame headers and
+ * mandatory fields.
+ */
+#define NL80211_FILS_DISCOVERY_TMPL_MIN_LEN 42
+
+/**
+ * enum nl80211_unsol_bcast_probe_resp_attributes - Unsolicited broadcast probe
+ * response configuration. Applicable only in 6GHz.
+ *
+ * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID: Invalid
+ *
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT: Maximum packet interval (u32, TU).
+ * Allowed range: 0..20 (TU = Time Unit). IEEE P802.11ax/D6.0
+ * 26.17.2.3.2 (AP behavior for fast passive scanning).
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response
+ * frame template (binary).
+ *
+ * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST: Internal
+ * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX: highest attribute
+ */
+enum nl80211_unsol_bcast_probe_resp_attributes {
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID,
+
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
+
+ /* keep last */
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST,
+ NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
+ __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
+};
+
+/**
+ * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE
+ * derivation. Applicable only when WPA3-Personal SAE authentication is
+ * used.
+ *
+ * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that
+ * attribute is not present from userspace.
+ * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only
+ * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only
+ * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element
+ * can be used.
+ */
+enum nl80211_sae_pwe_mechanism {
+ NL80211_SAE_PWE_UNSPECIFIED,
+ NL80211_SAE_PWE_HUNT_AND_PECK,
+ NL80211_SAE_PWE_HASH_TO_ELEMENT,
+ NL80211_SAE_PWE_BOTH,
+};
+
+/**
+ * enum nl80211_sar_type - type of SAR specs
+ *
+ * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
+ *
+ */
+enum nl80211_sar_type {
+ NL80211_SAR_TYPE_POWER,
+
+ /* add new type here */
+
+ /* Keep last */
+ NUM_NL80211_SAR_TYPE,
+};
+
+/**
+ * enum nl80211_sar_attrs - Attributes for SAR spec
+ *
+ * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
+ *
+ * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
+ * limit specifications. Each specification contains a set
+ * of %nl80211_sar_specs_attrs.
+ *
+ * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER
+ * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX.
+ *
+ * For sar_capa dump, it contains array of
+ * %NL80211_SAR_ATTR_SPECS_START_FREQ
+ * and %NL80211_SAR_ATTR_SPECS_END_FREQ.
+ *
+ * @__NL80211_SAR_ATTR_LAST: Internal
+ * @NL80211_SAR_ATTR_MAX: highest sar attribute
+ *
+ * These attributes are used with %NL80211_CMD_SET_SAR_SPEC
+ */
+enum nl80211_sar_attrs {
+ __NL80211_SAR_ATTR_INVALID,
+
+ NL80211_SAR_ATTR_TYPE,
+ NL80211_SAR_ATTR_SPECS,
+
+ __NL80211_SAR_ATTR_LAST,
+ NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
+ *
+ * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
+ * power limit value in units of 0.25 dBm if type is
+ * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
+ * 0 means userspace doesn't have SAR limitation on this associated range.
+ *
+ * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the
+ * index of exported freq range table and the associated power limitation
+ * is applied to this range.
+ *
+ * Userspace isn't required to set all the ranges advertised by WLAN driver,
+ * and userspace can skip some certain ranges. These skipped ranges don't
+ * have SAR limitations, and they are same as setting the
+ * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any
+ * value higher than regulatory allowed value just means SAR power
+ * limitation is removed, but it's required to set at least one range.
+ * It's not allowed to set duplicated range in one SET operation.
+ *
+ * Every SET operation overwrites previous SET operation.
+ *
+ * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @__NL80211_SAR_ATTR_SPECS_LAST: Internal
+ * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute
+ */
+enum nl80211_sar_specs_attrs {
+ __NL80211_SAR_ATTR_SPECS_INVALID,
+
+ NL80211_SAR_ATTR_SPECS_POWER,
+ NL80211_SAR_ATTR_SPECS_RANGE_INDEX,
+ NL80211_SAR_ATTR_SPECS_START_FREQ,
+ NL80211_SAR_ATTR_SPECS_END_FREQ,
+
+ __NL80211_SAR_ATTR_SPECS_LAST,
+ NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/contrib/wpa/src/drivers/priv_netlink.h b/contrib/wpa/src/drivers/priv_netlink.h
new file mode 100644
index 000000000000..d3f091c392b0
--- /dev/null
+++ b/contrib/wpa/src/drivers/priv_netlink.h
@@ -0,0 +1,109 @@
+/*
+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/*
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IFLA_IFNAME
+#define IFLA_IFNAME 3
+#endif
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+#ifndef IFLA_OPERSTATE
+#define IFLA_OPERSTATE 16
+#endif
+#ifndef IFLA_LINKMODE
+#define IFLA_LINKMODE 17
+#define IF_OPER_DORMANT 5
+#define IF_OPER_UP 6
+#endif
+
+#define NLM_F_REQUEST 1
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+#define RTM_DELLINK (RTM_BASE + 1)
+#define RTM_SETLINK (RTM_BASE + 3)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr *) \
+ (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (int) (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0))
+
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family;
+ unsigned short nl_pad;
+ u32 nl_pid;
+ u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+ u32 nlmsg_len;
+ u16 nlmsg_type;
+ u16 nlmsg_flags;
+ u32 nlmsg_seq;
+ u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */
diff --git a/contrib/wpa/src/drivers/rfkill.c b/contrib/wpa/src/drivers/rfkill.c
new file mode 100644
index 000000000000..4d4d1b4489fd
--- /dev/null
+++ b/contrib/wpa/src/drivers/rfkill.c
@@ -0,0 +1,224 @@
+/*
+ * Linux rfkill helper functions for driver wrappers
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+#include <limits.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "rfkill.h"
+
+#define RFKILL_EVENT_SIZE_V1 8
+
+struct rfkill_event {
+ u32 idx;
+ u8 type;
+ u8 op;
+ u8 soft;
+ u8 hard;
+} STRUCT_PACKED;
+
+enum rfkill_operation {
+ RFKILL_OP_ADD = 0,
+ RFKILL_OP_DEL,
+ RFKILL_OP_CHANGE,
+ RFKILL_OP_CHANGE_ALL,
+};
+
+enum rfkill_type {
+ RFKILL_TYPE_ALL = 0,
+ RFKILL_TYPE_WLAN,
+ RFKILL_TYPE_BLUETOOTH,
+ RFKILL_TYPE_UWB,
+ RFKILL_TYPE_WIMAX,
+ RFKILL_TYPE_WWAN,
+ RFKILL_TYPE_GPS,
+ RFKILL_TYPE_FM,
+ NUM_RFKILL_TYPES,
+};
+
+
+struct rfkill_data {
+ struct rfkill_config *cfg;
+ int fd;
+ int blocked;
+ uint32_t idx;
+};
+
+
+static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct rfkill_data *rfkill = eloop_ctx;
+ struct rfkill_event event;
+ ssize_t len;
+ int new_blocked;
+
+ len = read(rfkill->fd, &event, sizeof(event));
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+ strerror(errno));
+ return;
+ }
+ if (len != RFKILL_EVENT_SIZE_V1) {
+ wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+ "%d (expected %d)",
+ (int) len, RFKILL_EVENT_SIZE_V1);
+ return;
+ }
+ if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
+ return;
+
+ wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
+ "op=%u soft=%u hard=%u",
+ event.idx, event.type, event.op, event.soft,
+ event.hard);
+
+ if (event.hard) {
+ wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
+ new_blocked = 1;
+ } else if (event.soft) {
+ wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+ new_blocked = 1;
+ } else {
+ wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
+ new_blocked = 0;
+ }
+
+ if (new_blocked != rfkill->blocked) {
+ rfkill->blocked = new_blocked;
+ if (new_blocked)
+ rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
+ else
+ rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
+ }
+}
+
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
+{
+ struct rfkill_data *rfkill;
+ struct rfkill_event event;
+ ssize_t len;
+ char *phy = NULL, *rfk_phy;
+ char buf[24 + IFNAMSIZ + 1];
+ char buf2[31 + 11 + 1];
+ int found = 0;
+
+ rfkill = os_zalloc(sizeof(*rfkill));
+ if (rfkill == NULL)
+ return NULL;
+
+ os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
+ cfg->ifname);
+ phy = realpath(buf, NULL);
+ if (!phy) {
+ wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
+ goto fail;
+ }
+
+ rfkill->cfg = cfg;
+ rfkill->fd = open("/dev/rfkill", O_RDONLY);
+ if (rfkill->fd < 0) {
+ wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
+ "device");
+ goto fail;
+ }
+
+ if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
+ wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
+ "%s", strerror(errno));
+ goto fail2;
+ }
+
+ for (;;) {
+ len = read(rfkill->fd, &event, sizeof(event));
+ if (len < 0) {
+ if (errno == EAGAIN)
+ break; /* No more entries */
+ wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+ strerror(errno));
+ break;
+ }
+ if (len != RFKILL_EVENT_SIZE_V1) {
+ wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+ "%d (expected %d)",
+ (int) len, RFKILL_EVENT_SIZE_V1);
+ continue;
+ }
+ if (event.op != RFKILL_OP_ADD ||
+ event.type != RFKILL_TYPE_WLAN)
+ continue;
+
+ os_snprintf(buf2, sizeof(buf2),
+ "/sys/class/rfkill/rfkill%d/device", event.idx);
+ rfk_phy = realpath(buf2, NULL);
+ if (!rfk_phy)
+ goto fail2;
+ found = os_strcmp(phy, rfk_phy) == 0;
+ free(rfk_phy);
+
+ if (!found)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
+ "op=%u soft=%u hard=%u",
+ event.idx, event.type, event.op, event.soft,
+ event.hard);
+
+ rfkill->idx = event.idx;
+ if (event.hard) {
+ wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
+ rfkill->blocked = 1;
+ } else if (event.soft) {
+ wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+ rfkill->blocked = 1;
+ }
+ break;
+ }
+
+ if (!found)
+ goto fail2;
+
+ free(phy);
+ eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
+
+ return rfkill;
+
+fail2:
+ close(rfkill->fd);
+fail:
+ os_free(rfkill);
+ /* use standard free function to match realpath() */
+ free(phy);
+ return NULL;
+}
+
+
+void rfkill_deinit(struct rfkill_data *rfkill)
+{
+ if (rfkill == NULL)
+ return;
+
+ if (rfkill->fd >= 0) {
+ eloop_unregister_read_sock(rfkill->fd);
+ close(rfkill->fd);
+ }
+
+ os_free(rfkill->cfg);
+ os_free(rfkill);
+}
+
+
+int rfkill_is_blocked(struct rfkill_data *rfkill)
+{
+ if (rfkill == NULL)
+ return 0;
+
+ return rfkill->blocked;
+}
diff --git a/contrib/wpa/src/drivers/rfkill.h b/contrib/wpa/src/drivers/rfkill.h
new file mode 100644
index 000000000000..0412ac33054c
--- /dev/null
+++ b/contrib/wpa/src/drivers/rfkill.h
@@ -0,0 +1,25 @@
+/*
+ * Linux rfkill helper functions for driver wrappers
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RFKILL_H
+#define RFKILL_H
+
+struct rfkill_data;
+
+struct rfkill_config {
+ void *ctx;
+ char ifname[IFNAMSIZ];
+ void (*blocked_cb)(void *ctx);
+ void (*unblocked_cb)(void *ctx);
+};
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg);
+void rfkill_deinit(struct rfkill_data *rfkill);
+int rfkill_is_blocked(struct rfkill_data *rfkill);
+
+#endif /* RFKILL_H */
diff --git a/contrib/wpa/src/eap_common/Makefile b/contrib/wpa/src/eap_common/Makefile
new file mode 100644
index 000000000000..fd058a09a64d
--- /dev/null
+++ b/contrib/wpa/src/eap_common/Makefile
@@ -0,0 +1,18 @@
+LIB_OBJS= \
+ chap.o \
+ eap_common.o \
+ eap_eke_common.o \
+ eap_eke_common.o \
+ eap_fast_common.o \
+ eap_gpsk_common.o \
+ eap_ikev2_common.o \
+ eap_pax_common.o \
+ eap_peap_common.o \
+ eap_psk_common.o \
+ eap_pwd_common.o \
+ eap_sake_common.o \
+ eap_sim_common.o \
+ eap_wsc_common.o \
+ ikev2_common.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/eap_common/eap_common.c b/contrib/wpa/src/eap_common/eap_common.c
index 51a15d75bc93..e27b9652fa0a 100644
--- a/contrib/wpa/src/eap_common/eap_common.c
+++ b/contrib/wpa/src/eap_common/eap_common.c
@@ -63,7 +63,7 @@ int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
* the payload regardless of whether the packet used the expanded EAP header or
* not.
*/
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen)
{
const struct eap_hdr *hdr;
@@ -125,8 +125,8 @@ const u8 * eap_hdr_validate(int vendor, EapType eap_type,
* function to allocate the message buffers. The returned buffer has room for
* payload_len bytes and has the EAP header and Type field already filled in.
*/
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier)
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier)
{
struct wpabuf *buf;
struct eap_hdr *hdr;
@@ -196,7 +196,7 @@ u8 eap_get_id(const struct wpabuf *msg)
* @msg: Buffer starting with an EAP header
* Returns: The EAP Type after the EAP header
*/
-EapType eap_get_type(const struct wpabuf *msg)
+enum eap_type eap_get_type(const struct wpabuf *msg)
{
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
return EAP_TYPE_NONE;
diff --git a/contrib/wpa/src/eap_common/eap_common.h b/contrib/wpa/src/eap_common/eap_common.h
index e62f1676476e..e40cabee0764 100644
--- a/contrib/wpa/src/eap_common/eap_common.h
+++ b/contrib/wpa/src/eap_common/eap_common.h
@@ -20,13 +20,13 @@ struct erp_tlvs {
};
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen);
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier);
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier);
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
-EapType eap_get_type(const struct wpabuf *msg);
+enum eap_type eap_get_type(const struct wpabuf *msg);
int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
int stop_at_keyname);
diff --git a/contrib/wpa/src/eap_common/eap_defs.h b/contrib/wpa/src/eap_common/eap_defs.h
index bc3047c79c40..70999c4e3e17 100644
--- a/contrib/wpa/src/eap_common/eap_defs.h
+++ b/contrib/wpa/src/eap_common/eap_defs.h
@@ -64,7 +64,7 @@ enum eap_erp_cryptosuite {
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
*/
-typedef enum {
+enum eap_type {
EAP_TYPE_NONE = 0,
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
@@ -94,7 +94,7 @@ typedef enum {
EAP_TYPE_EKE = 53 /* RFC 6124 */,
EAP_TYPE_TEAP = 55 /* RFC 7170 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
-} EapType;
+};
/* SMI Network Management Private Enterprise Code for vendor specific types */
diff --git a/contrib/wpa/src/eap_common/eap_sim_common.c b/contrib/wpa/src/eap_common/eap_sim_common.c
index 1e0f80879daf..ab9bd86774b3 100644
--- a/contrib/wpa/src/eap_common/eap_sim_common.c
+++ b/contrib/wpa/src/eap_common/eap_sim_common.c
@@ -1210,17 +1210,45 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
}
+static const u8 * get_last_char(const u8 *val, size_t len, char c)
+{
+ while (len > 0) {
+ const u8 *pos = &val[len - 1];
+
+ if (*pos == (u8) c)
+ return pos;
+ len--;
+ }
+
+ return NULL;
+}
+
+
int eap_sim_anonymous_username(const u8 *id, size_t id_len)
{
static const char *anonymous_id_prefix = "anonymous@";
+ const u8 *decorated;
size_t anonymous_id_len = os_strlen(anonymous_id_prefix);
if (id_len > anonymous_id_len &&
os_memcmp(id, anonymous_id_prefix, anonymous_id_len) == 0)
return 1; /* 'anonymous@realm' */
+ if (id_len > anonymous_id_len + 1 &&
+ os_memcmp(id + 1, anonymous_id_prefix, anonymous_id_len) == 0)
+ return 1; /* 'Xanonymous@realm' where X is an EAP method code */
+
if (id_len > 1 && id[0] == '@')
return 1; /* '@realm' */
+ /* RFC 7542 decorated username, for example:
+ * homerealm.example.org!anonymous@otherrealm.example.net */
+ decorated = get_last_char(id, id_len, '!');
+ if (decorated) {
+ decorated++;
+ return eap_sim_anonymous_username(decorated,
+ id + id_len - decorated);
+ }
+
return 0;
}
diff --git a/contrib/wpa/src/eap_common/eap_teap_common.c b/contrib/wpa/src/eap_common/eap_teap_common.c
index fbca1b5e41c0..ffb9a6234243 100644
--- a/contrib/wpa/src/eap_common/eap_teap_common.c
+++ b/contrib/wpa/src/eap_common/eap_teap_common.c
@@ -17,6 +17,9 @@
#include "eap_teap_common.h"
+static int tls_cipher_suite_mac_sha384(u16 cs);
+
+
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
{
struct teap_tlv_hdr hdr;
@@ -67,24 +70,27 @@ struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf)
}
-static int eap_teap_tls_prf(const u8 *secret, size_t secret_len,
+static int eap_teap_tls_prf(u16 tls_cs, const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen)
{
/* TODO: TLS-PRF for TLSv1.3 */
+ if (tls_cipher_suite_mac_sha384(tls_cs))
+ return tls_prf_sha384(secret, secret_len, label, seed, seed_len,
+ out, outlen);
return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
out, outlen);
}
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
* MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Session Key Generating Function", (u8 *) "", 0,
msk, EAP_TEAP_KEY_LEN) < 0)
return -1;
@@ -94,7 +100,7 @@ int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
}
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk)
{
/*
* RFC 7170, Section 5.4: EAP Master Session Key Generation
@@ -102,7 +108,7 @@ int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
* "Extended Session Key Generating Function", 64)
*/
- if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
"Extended Session Key Generating Function",
(u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
return -1;
@@ -112,7 +118,7 @@ int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
}
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk, u8 *cmk)
{
u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
int res;
@@ -123,7 +129,7 @@ int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
* published. For now, derive CMK[0] based on S-IMCK[0] and
* IMSK of 32 octets of zeros. */
os_memset(imsk, 0, 32);
- res = eap_teap_tls_prf(s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, sizeof(imck));
if (res < 0)
@@ -136,7 +142,8 @@ int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
}
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -170,14 +177,16 @@ int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
context[0] = 0;
context[1] = 0;
context[2] = 64;
- if (eap_teap_tls_prf(emsk, emsk_len, "TEAPbindkey@ietf.org",
+ if (eap_teap_tls_prf(tls_cs, emsk, emsk_len,
+ "TEAPbindkey@ietf.org",
context, sizeof(context), imsk, 64) < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
imsk, 32);
- res = eap_teap_tls_prf(prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs,
+ prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -207,7 +216,7 @@ int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
}
- res = eap_teap_tls_prf(prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -418,6 +427,17 @@ int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
+ case TEAP_TLV_IDENTITY_TYPE:
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Identity-Type TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->identity_type = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Identity-Type: %u",
+ tlv->identity_type);
+ break;
case TEAP_TLV_RESULT:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
if (tlv->result) {
@@ -452,6 +472,15 @@ int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
tlv->nak = pos;
tlv->nak_len = len;
break;
+ case TEAP_TLV_ERROR:
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short Error TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->error_code = WPA_GET_BE32(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Error: %u", tlv->error_code);
+ break;
case TEAP_TLV_REQUEST_ACTION:
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
pos, len);
@@ -661,12 +690,29 @@ struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error)
}
-int eap_teap_allowed_anon_prov_phase2_method(u8 type)
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + 2);
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Identity-Type TLV(Identity-Type=%d)", id);
+ wpabuf_put_be16(buf, TEAP_TLV_IDENTITY_TYPE);
+ wpabuf_put_be16(buf, 2);
+ wpabuf_put_be16(buf, id);
+ return buf;
+}
+
+
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type)
{
/* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
* provide key generation, and be resistant to dictionary attack.
* Section 3.8 also mentions requirement for using EMSK Compound MAC. */
- return type == EAP_TYPE_PWD || type == EAP_TYPE_EKE;
+ return vendor == EAP_VENDOR_IETF &&
+ (type == EAP_TYPE_PWD || type == EAP_TYPE_EKE);
}
diff --git a/contrib/wpa/src/eap_common/eap_teap_common.h b/contrib/wpa/src/eap_common/eap_teap_common.h
index 585ec7c2f69a..3a25879499a0 100644
--- a/contrib/wpa/src/eap_common/eap_teap_common.h
+++ b/contrib/wpa/src/eap_common/eap_teap_common.h
@@ -151,6 +151,12 @@ enum teap_tlv_result_status {
TEAP_STATUS_FAILURE = 2
};
+/* Identity-Type values within Identity-Type TLV */
+enum teap_identity_types {
+ TEAP_IDENTITY_TYPE_USER = 1,
+ TEAP_IDENTITY_TYPE_MACHINE = 2,
+};
+
#define TEAP_TLV_MANDATORY 0x8000
#define TEAP_TLV_TYPE_MASK 0x3fff
@@ -188,6 +194,8 @@ struct eap_teap_tlv_parse {
size_t basic_auth_req_len;
u8 *basic_auth_resp;
size_t basic_auth_resp_len;
+ u32 error_code;
+ u16 identity_type;
};
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
@@ -195,10 +203,12 @@ void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len);
void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
const struct wpabuf *data);
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
-int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk);
-int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk);
-int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk);
-int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk);
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk);
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk,
+ u8 *cmk);
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -212,7 +222,9 @@ int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
const char * eap_teap_tlv_type_str(enum teap_tlv_types type);
struct wpabuf * eap_teap_tlv_result(int status, int intermediate);
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
-int eap_teap_allowed_anon_prov_phase2_method(u8 type);
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id);
+enum eap_type;
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type);
int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
#endif /* EAP_TEAP_H */
diff --git a/contrib/wpa/src/eap_peer/Makefile b/contrib/wpa/src/eap_peer/Makefile
new file mode 100644
index 000000000000..076d8c079081
--- /dev/null
+++ b/contrib/wpa/src/eap_peer/Makefile
@@ -0,0 +1,7 @@
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS= \
+ eap.o \
+ eap_methods.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/eap_peer/eap.c b/contrib/wpa/src/eap_peer/eap.c
index ac15e0e50761..7dcfe4fff45e 100644
--- a/contrib/wpa/src/eap_peer/eap.c
+++ b/contrib/wpa/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -32,12 +32,13 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_MAX_AUTH_ROUNDS 100
+#define EAP_MAX_AUTH_ROUNDS_SHORT 50
#define EAP_CLIENT_TIMEOUT_DEFAULT 60
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method);
+static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ enum eap_type method);
static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
static void eap_sm_processIdentity(struct eap_sm *sm,
const struct wpabuf *req);
@@ -53,14 +54,14 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
-static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+static bool eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
{
return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
}
static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
- Boolean value)
+ bool value)
{
sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
}
@@ -209,8 +210,8 @@ static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
/*
* This state initializes state machine variables when the machine is
- * activated (portEnabled = TRUE). This is also used when re-starting
- * authentication (eapRestart == TRUE).
+ * activated (portEnabled = true). This is also used when re-starting
+ * authentication (eapRestart == true).
*/
SM_STATE(EAP, INITIALIZE)
{
@@ -228,17 +229,17 @@ SM_STATE(EAP, INITIALIZE)
}
sm->selectedMethod = EAP_TYPE_NONE;
sm->methodState = METHOD_NONE;
- sm->allowNotifications = TRUE;
+ sm->allowNotifications = true;
sm->decision = DECISION_FAIL;
sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
- eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
- eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+ eapol_set_bool(sm, EAPOL_eapSuccess, false);
+ eapol_set_bool(sm, EAPOL_eapFail, false);
eap_sm_free_key(sm);
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
- sm->eapKeyAvailable = FALSE;
- eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+ sm->eapKeyAvailable = false;
+ eapol_set_bool(sm, EAPOL_eapRestart, false);
sm->lastId = -1; /* new session - make sure this does not match with
* the first EAP-Packet */
/*
@@ -246,36 +247,39 @@ SM_STATE(EAP, INITIALIZE)
* seemed to be able to trigger cases where both were set and if EAPOL
* state machine uses eapNoResp first, it may end up not sending a real
* reply correctly. This occurred when the workaround in FAIL state set
- * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+ * eapNoResp = true.. Maybe that workaround needs to be fixed to do
* something else(?)
*/
- eapol_set_bool(sm, EAPOL_eapResp, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapResp, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, false);
/*
* RFC 4137 does not reset ignore here, but since it is possible for
- * some method code paths to end up not setting ignore=FALSE, clear the
+ * some method code paths to end up not setting ignore=false, clear the
* value here to avoid issues if a previous authentication attempt
- * failed with ignore=TRUE being left behind in the last
+ * failed with ignore=true being left behind in the last
* m.check(eapReqData) operation.
*/
sm->ignore = 0;
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
- sm->reauthInit = FALSE;
+ sm->reauthInit = false;
sm->erp_seq = (u32) -1;
+ sm->use_machine_cred = 0;
}
/*
* This state is reached whenever service from the lower layer is interrupted
- * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
+ * or unavailable (portEnabled == false). Immediate transition to INITIALIZE
* occurs when the port becomes enabled.
*/
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
/*
* RFC 4137 does not describe clearing of idleWhile here, but doing so
* allows the timer tick to be stopped more quickly when EAP is not in
@@ -297,7 +301,7 @@ SM_STATE(EAP, IDLE)
/*
- * This state is entered when an EAP packet is received (eapReq == TRUE) to
+ * This state is entered when an EAP packet is received (eapReq == true) to
* parse the packet header.
*/
SM_STATE(EAP, RECEIVED)
@@ -309,6 +313,10 @@ SM_STATE(EAP, RECEIVED)
/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
eap_sm_parseEapReq(sm, eapReqData);
sm->num_rounds++;
+ if (!eapReqData || wpabuf_len(eapReqData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -319,7 +327,7 @@ SM_STATE(EAP, RECEIVED)
SM_STATE(EAP, GET_METHOD)
{
int reinit;
- EapType method;
+ enum eap_type method;
const struct eap_method *eap_method;
SM_ENTRY(EAP, GET_METHOD);
@@ -815,7 +823,8 @@ struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
erp->keyname_nai, erp->next_seq);
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
@@ -857,7 +866,7 @@ static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
wpabuf_free(sm->eapRespData);
sm->eapRespData = msg;
- sm->reauthInit = TRUE;
+ sm->reauthInit = true;
return 0;
}
#endif /* CONFIG_ERP */
@@ -949,18 +958,20 @@ SM_STATE(EAP, SEND_RESPONSE)
SM_ENTRY(EAP, SEND_RESPONSE);
wpabuf_free(sm->lastRespData);
if (sm->eapRespData) {
+ if (wpabuf_len(sm->eapRespData) >= 20)
+ sm->num_rounds_short = 0;
if (sm->workaround)
os_memcpy(sm->last_sha1, sm->req_sha1, 20);
sm->lastId = sm->reqId;
sm->lastRespData = wpabuf_dup(sm->eapRespData);
- eapol_set_bool(sm, EAPOL_eapResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapResp, true);
} else {
wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
sm->lastRespData = NULL;
}
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
- sm->reauthInit = FALSE;
+ sm->reauthInit = false;
}
@@ -971,8 +982,8 @@ SM_STATE(EAP, SEND_RESPONSE)
SM_STATE(EAP, DISCARD)
{
SM_ENTRY(EAP, DISCARD);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
}
@@ -1037,15 +1048,15 @@ SM_STATE(EAP, SUCCESS)
SM_ENTRY(EAP, SUCCESS);
if (sm->eapKeyData != NULL)
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
/*
* RFC 4137 does not clear eapReq here, but this seems to be required
* to avoid processing the same request twice when state machine is
* initialized.
*/
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
/*
* RFC 4137 does not set eapNoResp here, but this seems to be required
@@ -1053,11 +1064,25 @@ SM_STATE(EAP, SUCCESS)
* addition, either eapResp or eapNoResp is required to be set after
* processing the received EAP frame.
*/
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP authentication completed successfully");
+ if (!config || !sm->m) {
+ /*
+ * This should not happen under normal conditions, but be more
+ * careful here since there was an earlier case where
+ * EAP-Success could end up getting delivered to the state
+ * machine for processing after the state had been cleaned with
+ * a call to eap_invalidate_cached_session() (and also
+ * eapol_sm_notify_config() having been used to clear EAP
+ * configuration in the EAPOL state machine).
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: State machine not configured - cannot initialize ERP");
+ return;
+ }
if (config->erp && sm->m->get_emsk && sm->eapSessionId &&
sm->m->isKeyAvailable &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv))
@@ -1072,21 +1097,21 @@ SM_STATE(EAP, SUCCESS)
SM_STATE(EAP, FAILURE)
{
SM_ENTRY(EAP, FAILURE);
- eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+ eapol_set_bool(sm, EAPOL_eapFail, true);
/*
* RFC 4137 does not clear eapReq here, but this seems to be required
* to avoid processing the same request twice when state machine is
* initialized.
*/
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
/*
* RFC 4137 does not set eapNoResp here. However, either eapResp or
* eapNoResp is required to be set after processing the received EAP
* frame.
*/
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
"EAP authentication failed");
@@ -1341,6 +1366,14 @@ SM_STEP(EAP)
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) {
+ if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: more than %d authentication rounds (short) - abort",
+ EAP_MAX_AUTH_ROUNDS_SHORT);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else {
/* Local transitions */
eap_peer_sm_step_local(sm);
@@ -1348,19 +1381,19 @@ SM_STEP(EAP)
}
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method)
+static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ enum eap_type method)
{
if (!eap_allowed_method(sm, vendor, method)) {
wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
"vendor %u method %u", vendor, method);
- return FALSE;
+ return false;
}
if (eap_peer_get_eap_method(vendor, method))
- return TRUE;
+ return true;
wpa_printf(MSG_DEBUG, "EAP: not included in build: "
"vendor %u method %u", vendor, method);
- return FALSE;
+ return false;
}
@@ -1595,13 +1628,13 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
static int eap_sm_set_scard_pin(struct eap_sm *sm,
struct eap_peer_config *conf)
{
- if (scard_set_pin(sm->scard_ctx, conf->pin)) {
+ if (scard_set_pin(sm->scard_ctx, conf->cert.pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
* blocking SIM.
*/
- os_free(conf->pin);
- conf->pin = NULL;
+ os_free(conf->cert.pin);
+ conf->cert.pin = NULL;
wpa_printf(MSG_WARNING, "PIN validation failed");
eap_sm_request_pin(sm);
@@ -1657,6 +1690,11 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
identity_len = config->anonymous_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
identity, identity_len);
+ } else if (sm->use_machine_cred) {
+ identity = config->machine_identity;
+ identity_len = config->machine_identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -1778,7 +1816,7 @@ invalid:
#endif /* CONFIG_ERP */
wpa_printf(MSG_DEBUG,
"EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
- eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
+ eapol_set_bool(sm, EAPOL_eapTriggerStart, true);
}
@@ -1902,9 +1940,9 @@ no_auth_tag:
if (flags & 0x80 || !auth_tag_ok) {
wpa_printf(MSG_DEBUG,
"EAP: EAP-Finish/Re-auth indicated failure");
- eapol_set_bool(sm, EAPOL_eapFail, TRUE);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapFail, true);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
"EAP authentication failed");
sm->prev_failure = 1;
@@ -1933,10 +1971,10 @@ no_auth_tag:
}
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
sm->eapKeyData, sm->eapKeyDataLen);
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP re-authentication completed successfully");
#endif /* CONFIG_ERP */
@@ -1949,7 +1987,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
size_t plen;
const u8 *pos;
- sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
+ sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = false;
sm->reqId = 0;
sm->reqMethod = EAP_TYPE_NONE;
sm->reqVendor = EAP_VENDOR_IETF;
@@ -1983,7 +2021,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
"no Type field");
return;
}
- sm->rxReq = TRUE;
+ sm->rxReq = true;
pos = (const u8 *) (hdr + 1);
sm->reqMethod = *pos++;
if (sm->reqMethod == EAP_TYPE_EXPANDED) {
@@ -2014,7 +2052,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
"EAP-Response - no Type field");
return;
}
- sm->rxResp = TRUE;
+ sm->rxResp = true;
pos = (const u8 *) (hdr + 1);
sm->reqMethod = *pos;
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
@@ -2027,7 +2065,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
case EAP_CODE_SUCCESS:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
eap_notify_status(sm, "completion", "success");
- sm->rxSuccess = TRUE;
+ sm->rxSuccess = true;
break;
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
@@ -2041,7 +2079,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
if (error_code != NO_EAP_METHOD_ERROR)
eap_report_error(sm, error_code);
}
- sm->rxFailure = TRUE;
+ sm->rxFailure = true;
break;
case EAP_CODE_INITIATE:
eap_peer_initiate(sm, hdr, plen);
@@ -2209,7 +2247,7 @@ int eap_peer_sm_step(struct eap_sm *sm)
{
int res = 0;
do {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(EAP);
if (sm->changed)
res = 1;
@@ -2238,7 +2276,7 @@ void eap_sm_abort(struct eap_sm *sm)
/* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get
* cleared for the next authentication. */
- eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+ eapol_set_bool(sm, EAPOL_eapSuccess, false);
}
@@ -2600,6 +2638,8 @@ void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
static int eap_allowed_phase2_type(int vendor, int type)
{
+ if (vendor == EAP_VENDOR_HOSTAP)
+ return 1;
if (vendor != EAP_VENDOR_IETF)
return 0;
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
@@ -2662,7 +2702,7 @@ struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
if (eap_allowed_phase2_type(vendor, method)) {
if (vendor == EAP_VENDOR_IETF &&
method == EAP_TYPE_TLS && config &&
- config->private_key2 == NULL)
+ !config->phase2_cert.private_key)
continue;
buf[*count].vendor = vendor;
buf[*count].method = method;
@@ -2721,8 +2761,15 @@ struct eap_peer_config * eap_get_config(struct eap_sm *sm)
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
+
+ if (sm->use_machine_cred) {
+ *len = config->machine_identity_len;
+ return config->machine_identity;
+ }
+
*len = config->identity_len;
return config->identity;
}
@@ -2732,14 +2779,24 @@ static int eap_get_ext_password(struct eap_sm *sm,
struct eap_peer_config *config)
{
char *name;
+ const u8 *password;
+ size_t password_len;
+
+ if (sm->use_machine_cred) {
+ password = config->machine_password;
+ password_len = config->machine_password_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
- if (config->password == NULL)
+ if (!password)
return -1;
- name = os_zalloc(config->password_len + 1);
- if (name == NULL)
+ name = os_zalloc(password_len + 1);
+ if (!name)
return -1;
- os_memcpy(name, config->password, config->password_len);
+ os_memcpy(name, password, password_len);
ext_password_free(sm->ext_pw_buf);
sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@@ -2758,16 +2815,25 @@ static int eap_get_ext_password(struct eap_sm *sm,
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ return config->machine_password;
+ }
+
*len = config->password_len;
return config->password;
}
@@ -2785,10 +2851,14 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
if (hash)
@@ -2797,6 +2867,14 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ if (hash)
+ *hash = !!(config->flags &
+ EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
+ return config->machine_password;
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
@@ -2941,8 +3019,8 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
return;
if (sm->eapKeyData != NULL)
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP authentication completed successfully (based on lower "
"layer success)");
diff --git a/contrib/wpa/src/eap_peer/eap.h b/contrib/wpa/src/eap_peer/eap.h
index acd70d05d169..a40d007d9960 100644
--- a/contrib/wpa/src/eap_peer/eap.h
+++ b/contrib/wpa/src/eap_peer/eap.h
@@ -44,7 +44,7 @@ enum eapol_bool_var {
/**
* EAPOL_eapRestart - Lower layer request to restart authentication
*
- * Set to TRUE in lower layer, FALSE in EAP state machine.
+ * Set to true in lower layer, false in EAP state machine.
*/
EAPOL_eapRestart,
@@ -58,21 +58,21 @@ enum eapol_bool_var {
/**
* EAPOL_eapResp - Response to send
*
- * Set to TRUE in EAP state machine, FALSE in lower layer.
+ * Set to true in EAP state machine, false in lower layer.
*/
EAPOL_eapResp,
/**
* EAPOL_eapNoResp - Request has been process; no response to send
*
- * Set to TRUE in EAP state machine, FALSE in lower layer.
+ * Set to true in EAP state machine, false in lower layer.
*/
EAPOL_eapNoResp,
/**
* EAPOL_eapReq - EAP request available from lower layer
*
- * Set to TRUE in lower layer, FALSE in EAP state machine.
+ * Set to true in lower layer, false in EAP state machine.
*/
EAPOL_eapReq,
@@ -147,7 +147,7 @@ struct eapol_callbacks {
* @variable: EAPOL boolean variable to get
* Returns: Value of the EAPOL variable
*/
- Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+ bool (*get_bool)(void *ctx, enum eapol_bool_var variable);
/**
* set_bool - Set a boolean EAPOL state variable
@@ -155,8 +155,7 @@ struct eapol_callbacks {
* @variable: EAPOL boolean variable to set
* @value: Value for the EAPOL variable
*/
- void (*set_bool)(void *ctx, enum eapol_bool_var variable,
- Boolean value);
+ void (*set_bool)(void *ctx, enum eapol_bool_var variable, bool value);
/**
* get_int - Get an integer EAPOL state variable
diff --git a/contrib/wpa/src/eap_peer/eap_aka.c b/contrib/wpa/src/eap_peer/eap_aka.c
index d50bc6186d91..8c475f13f162 100644
--- a/contrib/wpa/src/eap_peer/eap_aka.c
+++ b/contrib/wpa/src/eap_peer/eap_aka.c
@@ -442,19 +442,28 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
static int eap_aka_add_id_msg(struct eap_aka_data *data,
- const struct wpabuf *msg)
+ const struct wpabuf *msg1,
+ const struct wpabuf *msg2)
{
- if (msg == NULL)
+ size_t len;
+
+ if (!msg1)
return -1;
+ len = wpabuf_len(msg1);
+ if (msg2)
+ len += wpabuf_len(msg2);
- if (data->id_msgs == NULL) {
- data->id_msgs = wpabuf_dup(msg);
- return data->id_msgs == NULL ? -1 : 0;
+ if (!data->id_msgs) {
+ data->id_msgs = wpabuf_alloc(len);
+ if (!data->id_msgs)
+ return -1;
+ } else if (wpabuf_resize(&data->id_msgs, len) < 0) {
+ return -1;
}
- if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
- return -1;
- wpabuf_put_buf(data->id_msgs, msg);
+ wpabuf_put_buf(data->id_msgs, msg1);
+ if (msg2)
+ wpabuf_put_buf(data->id_msgs, msg2);
return 0;
}
@@ -799,8 +808,13 @@ static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
buf = eap_aka_response_identity(sm, data, id, attr->id_req);
if (data->prev_id != id) {
- eap_aka_add_id_msg(data, reqData);
- eap_aka_add_id_msg(data, buf);
+ if (eap_aka_add_id_msg(data, reqData, buf) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to store ID messages");
+ wpabuf_free(buf);
+ return eap_aka_client_error(
+ data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
data->prev_id = id;
}
@@ -1365,24 +1379,24 @@ static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
eap_sm_request_identity(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
&len);
if (pos == NULL || len < 3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
req = wpabuf_head(reqData);
id = req->identifier;
len = be_to_host16(req->length);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
@@ -1441,14 +1455,14 @@ done:
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return res;
}
-static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->pseudonym || data->reauth_id;
@@ -1497,7 +1511,7 @@ static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
}
-static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_config.h b/contrib/wpa/src/eap_peer/eap_config.h
index 148c9066d27c..3238f74f955a 100644
--- a/contrib/wpa/src/eap_peer/eap_config.h
+++ b/contrib/wpa/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
/*
* EAP peer configuration data
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,68 +10,9 @@
#define EAP_CONFIG_H
/**
- * struct eap_peer_config - EAP peer configuration/credentials
+ * struct eap_peer_cert_config - EAP peer certificate configuration/credential
*/
-struct eap_peer_config {
- /**
- * identity - EAP Identity
- *
- * This field is used to set the real user identity or NAI (for
- * EAP-PSK/PAX/SAKE/GPSK).
- */
- u8 *identity;
-
- /**
- * identity_len - EAP Identity length
- */
- size_t identity_len;
-
- /**
- * anonymous_identity - Anonymous EAP Identity
- *
- * This field is used for unencrypted use with EAP types that support
- * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
- * real identity (identity field) only to the authentication server.
- *
- * If not set, the identity field will be used for both unencrypted and
- * protected fields.
- *
- * This field can also be used with EAP-SIM/AKA/AKA' to store the
- * pseudonym identity.
- */
- u8 *anonymous_identity;
-
- /**
- * anonymous_identity_len - Length of anonymous_identity
- */
- size_t anonymous_identity_len;
-
- u8 *imsi_identity;
- size_t imsi_identity_len;
-
- /**
- * password - Password string for EAP
- *
- * This field can include either the plaintext password (default
- * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
- * presentation of the password) if flags field has
- * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
- * only be used with authentication mechanism that use this hash as the
- * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
- * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
- *
- * In addition, this field is used to configure a pre-shared key for
- * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
- * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
- * PSK.
- */
- u8 *password;
-
- /**
- * password_len - Length of password field
- */
- size_t password_len;
-
+struct eap_peer_cert_config {
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
@@ -231,14 +172,6 @@ struct eap_peer_config {
char *check_cert_subject;
/**
- * check_cert_subject2 - Constraint for server certificate subject fields
- *
- * This field is like check_cert_subject, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *check_cert_subject2;
-
- /**
* altsubject_match - Constraint for server certificate alt. subject
*
* Semicolon separated string of entries to be matched against the
@@ -299,115 +232,181 @@ struct eap_peer_config {
char *domain_match;
/**
- * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+ * pin - PIN for USIM, GSM SIM, and smartcards
*
- * This file can have one or more trusted CA certificates. If ca_cert2
- * and ca_path2 are not included, server certificate will not be
- * verified. This is insecure and a trusted CA certificate should
- * always be configured. Full path to the file should be used since
- * working directory may change when wpa_supplicant is run in the
- * background.
+ * This field is used to configure PIN for SIM and smartcards for
+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+ * smartcard is used for private key operations.
*
- * This field is like ca_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * If left out, this will be asked through control interface.
+ */
+ char *pin;
+
+ /**
+ * engine - Enable OpenSSL engine (e.g., for smartcard access)
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *ca_cert2;
+ int engine;
/**
- * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+ * engine_id - Engine ID for OpenSSL engine
*
- * This path may contain multiple CA certificates in OpenSSL format.
- * Common use for this is to point to system trusted CA list which is
- * often installed into directory like /etc/ssl/certs. If configured,
- * these certificates are added to the list of trusted CAs. ca_cert
- * may also be included in that case, but it is not required.
+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+ * engine.
*
- * This field is like ca_path, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *ca_path2;
+ char *engine_id;
+
/**
- * client_cert2 - File path to client certificate file
+ * key_id - Key ID for OpenSSL engine
*
- * This field is like client_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *key_id;
+
+ /**
+ * cert_id - Cert ID for OpenSSL engine
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *client_cert2;
+ char *cert_id;
/**
- * private_key2 - File path to client private key file
+ * ca_cert_id - CA Cert ID for OpenSSL engine
*
- * This field is like private_key, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
+ */
+ char *ca_cert_id;
+
+ /**
+ * ocsp - Whether to use/require OCSP to check server certificate
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
*/
- char *private_key2;
+ int ocsp;
+};
+/**
+ * struct eap_peer_config - EAP peer configuration/credentials
+ */
+struct eap_peer_config {
/**
- * private_key2_passwd - Password for private key file
+ * identity - EAP Identity
*
- * This field is like private_key_passwd, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This field is used to set the real user identity or NAI (for
+ * EAP-PSK/PAX/SAKE/GPSK).
+ */
+ u8 *identity;
+
+ /**
+ * identity_len - EAP Identity length
*/
- char *private_key2_passwd;
+ size_t identity_len;
/**
- * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+ * anonymous_identity - Anonymous EAP Identity
*
- * This field is like dh_file, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * This field is used for unencrypted use with EAP types that support
+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+ * real identity (identity field) only to the authentication server.
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * If not set, the identity field will be used for both unencrypted and
+ * protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
- char *dh_file2;
+ u8 *anonymous_identity;
/**
- * subject_match2 - Constraint for server certificate subject
+ * anonymous_identity_len - Length of anonymous_identity
+ */
+ size_t anonymous_identity_len;
+
+ u8 *imsi_identity;
+ size_t imsi_identity_len;
+
+ /**
+ * machine_identity - EAP Identity for machine credential
+ *
+ * This field is used to set the machine identity or NAI for cases where
+ * and explicit machine credential (instead of or in addition to a user
+ * credential (from %identity) is needed.
+ */
+ u8 *machine_identity;
+
+ /**
+ * machine_identity_len - EAP Identity length for machine credential
+ */
+ size_t machine_identity_len;
+
+ /**
+ * password - Password string for EAP
+ *
+ * This field can include either the plaintext password (default
+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+ * presentation of the password) if flags field has
+ * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+ * only be used with authentication mechanism that use this hash as the
+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
*
- * This field is like subject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * In addition, this field is used to configure a pre-shared key for
+ * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
+ * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
+ * PSK.
*/
- char *subject_match2;
+ u8 *password;
/**
- * altsubject_match2 - Constraint for server certificate alt. subject
+ * password_len - Length of password field
+ */
+ size_t password_len;
+
+ /**
+ * machine_password - Password string for EAP machine credential
*
- * This field is like altsubject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This field is used when machine credential based on username/password
+ * is needed instead of a user credential (from %password). See
+ * %password for more details on the format.
+ */
+ u8 *machine_password;
+
+ /**
+ * machine_password_len - Length of machine credential password field
+ */
+ size_t machine_password_len;
+
+ /**
+ * cert - Certificate parameters for Phase 1
*/
- char *altsubject_match2;
+ struct eap_peer_cert_config cert;
/**
- * domain_suffix_match2 - Constraint for server domain name
+ * phase2_cert - Certificate parameters for Phase 2
*
- * This field is like domain_suffix_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is like cert, but used for Phase 2 (inside
+ * EAP-TTLS/PEAP/FAST/TEAP tunnel) authentication.
*/
- char *domain_suffix_match2;
+ struct eap_peer_cert_config phase2_cert;
/**
- * domain_match2 - Constraint for server domain name
+ * machine_cert - Certificate parameters for Phase 2 machine credential
*
- * This field is like domain_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is like cert, but used for Phase 2 (inside EAP-TEAP tunnel)
+ * authentication with machine credentials (while phase2_cert is used
+ * for user credentials).
*/
- char *domain_match2;
+ struct eap_peer_cert_config machine_cert;
/**
* eap_methods - Allowed EAP methods
@@ -496,6 +495,13 @@ struct eap_peer_config {
char *phase2;
/**
+ * machine_phase2 - Phase2 parameters for machine credentials
+ *
+ * See phase2 for more details.
+ */
+ char *machine_phase2;
+
+ /**
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
*
* This field is used to configure PC/SC smartcard interface.
@@ -507,123 +513,6 @@ struct eap_peer_config {
char *pcsc;
/**
- * pin - PIN for USIM, GSM SIM, and smartcards
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin;
-
- /**
- * engine - Enable OpenSSL engine (e.g., for smartcard access)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- int engine;
-
- /**
- * engine_id - Engine ID for OpenSSL engine
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *engine_id;
-
- /**
- * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- int engine2;
-
-
- /**
- * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * This field is like pin2, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin2;
-
- /**
- * engine2_id - Engine ID for OpenSSL engine (Phase 2)
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine_id, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *engine2_id;
-
-
- /**
- * key_id - Key ID for OpenSSL engine
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key_id;
-
- /**
- * cert_id - Cert ID for OpenSSL engine
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert_id;
-
- /**
- * ca_cert_id - CA Cert ID for OpenSSL engine
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert_id;
-
- /**
- * key2_id - Key ID for OpenSSL engine (phase2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key2_id;
-
- /**
- * cert2_id - Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert2_id;
-
- /**
- * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert2_id;
-
- /**
* otp - One-time-password
*
* This field should not be set in configuration step. It is only used
@@ -751,6 +640,8 @@ struct eap_peer_config {
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
+#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
/**
* flags - Network configuration flags (bitfield)
*
@@ -760,19 +651,14 @@ struct eap_peer_config {
* instead of plaintext password
* bit 1 = password is stored in external storage; the value in the
* password field is the name of that external entry
+ * bit 2 = machine password is represented as a 16-byte NtPasswordHash
+ * value instead of plaintext password
+ * bit 3 = machine password is stored in external storage; the value in
+ * the password field is the name of that external entry
*/
u32 flags;
/**
- * ocsp - Whether to use/require OCSP to check server certificate
- *
- * 0 = do not use OCSP stapling (TLS certificate status extension)
- * 1 = try to use OCSP stapling, but not require response
- * 2 = require valid OCSP stapling response
- */
- int ocsp;
-
- /**
* external_sim_resp - Response from external SIM processing
*
* This field should not be set in configuration step. It is only used
diff --git a/contrib/wpa/src/eap_peer/eap_eke.c b/contrib/wpa/src/eap_peer/eap_eke.c
index 534af262e88a..90294427088a 100644
--- a/contrib/wpa/src/eap_peer/eap_eke.c
+++ b/contrib/wpa/src/eap_peer/eap_eke.c
@@ -211,7 +211,7 @@ static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
eap_eke_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -617,7 +617,7 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
eap_eke_state(data, SUCCESS);
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -656,7 +656,7 @@ static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -666,10 +666,10 @@ static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (eke_exch) {
case EAP_EKE_ID:
@@ -689,18 +689,18 @@ static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
break;
default:
wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE)
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
-static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_fast.c b/contrib/wpa/src/eap_peer/eap_fast.c
index 94ce57d6219f..b12cfee31ad8 100644
--- a/contrib/wpa/src/eap_peer/eap_fast.c
+++ b/contrib/wpa/src/eap_peer/eap_fast.c
@@ -162,7 +162,7 @@ static void * eap_fast_init(struct eap_sm *sm)
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -364,22 +364,24 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm,
}
-static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
+static int eap_fast_select_phase2_method(struct eap_fast_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
/* TODO: TNC with anonymous provisioning; need to require both
* completed MSCHAPv2 and TNC */
- if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
- wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
- "during unauthenticated provisioning; reject phase2"
- " type %d", type);
+ if (data->anon_provisioning &&
+ (vendor != EAP_VENDOR_IETF || type != EAP_TYPE_MSCHAPV2)) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated provisioning; reject phase2 type %u:%u",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
@@ -391,7 +393,7 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -404,7 +406,9 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
@@ -422,6 +426,8 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-FAST: too short "
@@ -429,14 +435,27 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
"deinitialize previous method");
data->phase2_method->deinit(sm, data->phase2_priv);
@@ -448,7 +467,7 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_fast_select_phase2_method(data, *pos) < 0) {
+ eap_fast_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -459,8 +478,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
if ((data->phase2_priv == NULL &&
eap_fast_init_phase2_method(sm, data) < 0) ||
data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
- "Phase 2 EAP method %d", *pos);
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
@@ -1668,7 +1688,7 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
#if 0 /* FIX */
-static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
@@ -1734,7 +1754,7 @@ static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
}
-static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->success;
diff --git a/contrib/wpa/src/eap_peer/eap_gpsk.c b/contrib/wpa/src/eap_peer/eap_gpsk.c
index f9c4d3773bf7..20d96c139bab 100644
--- a/contrib/wpa/src/eap_peer/eap_gpsk.c
+++ b/contrib/wpa/src/eap_peer/eap_gpsk.c
@@ -280,7 +280,7 @@ static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
struct wpabuf *resp;
if (data->state != GPSK_1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -588,7 +588,7 @@ static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
const u8 *pos, *end;
if (data->state != GPSK_3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -671,7 +671,7 @@ static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -680,10 +680,10 @@ static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
len--;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
switch (opcode) {
case EAP_GPSK_OPCODE_GPSK_1:
@@ -696,7 +696,7 @@ static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG,
"EAP-GPSK: Ignoring message with unknown opcode %d",
opcode);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -704,7 +704,7 @@ static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_gtc.c b/contrib/wpa/src/eap_peer/eap_gtc.c
index a519a780a90b..72c02cc19a36 100644
--- a/contrib/wpa/src/eap_peer/eap_gtc.c
+++ b/contrib/wpa/src/eap_peer/eap_gtc.c
@@ -54,7 +54,7 @@ static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
id = eap_get_id(reqData);
@@ -85,15 +85,15 @@ static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
eap_sm_request_otp(sm, (const char *) pos, len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
plen = password_len;
identity = eap_get_config_identity(sm, &identity_len);
diff --git a/contrib/wpa/src/eap_peer/eap_i.h b/contrib/wpa/src/eap_peer/eap_i.h
index 096f0f28efca..f43891e39d1c 100644
--- a/contrib/wpa/src/eap_peer/eap_i.h
+++ b/contrib/wpa/src/eap_peer/eap_i.h
@@ -38,7 +38,7 @@ struct eap_method_ret {
/**
* ignore - Whether method decided to drop the current packed (OUT)
*/
- Boolean ignore;
+ bool ignore;
/**
* methodState - Method-specific state (IN/OUT)
@@ -53,7 +53,7 @@ struct eap_method_ret {
/**
* allowNotifications - Whether method allows notifications (OUT)
*/
- Boolean allowNotifications;
+ bool allowNotifications;
};
@@ -72,7 +72,7 @@ struct eap_method {
/**
* method - EAP type number (EAP_TYPE_*)
*/
- EapType method;
+ enum eap_type method;
/**
* name - Name of the method (e.g., "TLS")
@@ -123,9 +123,9 @@ struct eap_method {
* isKeyAvailable - Find out whether EAP method has keying material
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
- * Returns: %TRUE if key material (eapKeyData) is available
+ * Returns: %true if key material (eapKeyData) is available
*/
- Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
+ bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);
/**
* getKey - Get EAP method specific keying material (eapKeyData)
@@ -161,13 +161,13 @@ struct eap_method {
* has_reauth_data - Whether method is ready for fast reauthentication
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
- * Returns: %TRUE or %FALSE based on whether fast reauthentication is
+ * Returns: %true or %false based on whether fast reauthentication is
* possible
*
* This function is an optional handler that only EAP methods
* supporting fast re-authentication need to implement.
*/
- Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
+ bool (*has_reauth_data)(struct eap_sm *sm, void *priv);
/**
* deinit_for_reauth - Release data that is not needed for fast re-auth
@@ -312,45 +312,45 @@ struct eap_sm {
EAP_FAILURE
} EAP_state;
/* Long-term local variables */
- EapType selectedMethod;
+ enum eap_type selectedMethod;
EapMethodState methodState;
int lastId;
struct wpabuf *lastRespData;
EapDecision decision;
/* Short-term local variables */
- Boolean rxReq;
- Boolean rxSuccess;
- Boolean rxFailure;
+ bool rxReq;
+ bool rxSuccess;
+ bool rxFailure;
int reqId;
- EapType reqMethod;
+ enum eap_type reqMethod;
int reqVendor;
u32 reqVendorMethod;
- Boolean ignore;
+ bool ignore;
/* Constants */
int ClientTimeout;
/* Miscellaneous variables */
- Boolean allowNotifications; /* peer state machine <-> methods */
+ bool allowNotifications; /* peer state machine <-> methods */
struct wpabuf *eapRespData; /* peer to lower layer */
- Boolean eapKeyAvailable; /* peer to lower layer */
+ bool eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
u8 *eapSessionId; /* peer to lower layer */
size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
- Boolean changed;
+ bool changed;
void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
int init_phase2;
int fast_reauth;
- Boolean reauthInit; /* send EAP-Identity/Re-auth */
+ bool reauthInit; /* send EAP-Identity/Re-auth */
u32 erp_seq;
- Boolean rxResp /* LEAP only */;
- Boolean leap_done;
- Boolean peap_done;
+ bool rxResp /* LEAP only */;
+ bool leap_done;
+ bool peap_done;
u8 req_sha1[20]; /* SHA1() of the current EAP packet */
u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used
* in duplicate request detection. */
@@ -366,6 +366,7 @@ struct eap_sm {
u8 *peer_challenge, *auth_challenge;
int num_rounds;
+ int num_rounds_short;
int force_disabled;
struct wps_context *wps;
@@ -381,6 +382,7 @@ struct eap_sm {
unsigned int expected_failure:1;
unsigned int ext_cert_check:1;
unsigned int waiting_ext_cert_check:1;
+ unsigned int use_machine_cred:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/contrib/wpa/src/eap_peer/eap_ikev2.c b/contrib/wpa/src/eap_peer/eap_ikev2.c
index 6ddf50835ade..b49fe1672c4a 100644
--- a/contrib/wpa/src/eap_peer/eap_ikev2.c
+++ b/contrib/wpa/src/eap_peer/eap_ikev2.c
@@ -138,9 +138,9 @@ static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
u8 flags;
size_t send_len, plen, icv_len = 0;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = 0;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -293,7 +293,7 @@ static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
"a fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -303,14 +303,14 @@ static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
/* Limit maximum memory allocation */
wpa_printf(MSG_DEBUG,
"EAP-IKEV2: Ignore too long message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpabuf_put_data(data->in_buf, buf, len);
@@ -320,7 +320,7 @@ static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
(unsigned long) wpabuf_tailroom(data->in_buf));
}
- ret->ignore = FALSE;
+ ret->ignore = false;
return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
}
@@ -338,7 +338,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -355,14 +355,14 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
if (eap_ikev2_process_icv(data, reqData, flags, pos, &end,
data->state == WAIT_FRAG_ACK && len == 0) < 0)
{
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
if (end - pos < 4) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE32(pos);
@@ -372,7 +372,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -384,7 +384,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
if (len != 0) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
"in WAIT_FRAG_ACK state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
@@ -393,10 +393,10 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
}
if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
return eap_ikev2_process_fragment(data, ret, id, flags,
message_length, pos,
@@ -435,7 +435,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE && data->keymat_ok;
diff --git a/contrib/wpa/src/eap_peer/eap_leap.c b/contrib/wpa/src/eap_peer/eap_leap.c
index 34758e021149..02daddfb4413 100644
--- a/contrib/wpa/src/eap_peer/eap_leap.c
+++ b/contrib/wpa/src/eap_peer/eap_leap.c
@@ -45,7 +45,7 @@ static void * eap_leap_init(struct eap_sm *sm)
return NULL;
data->state = LEAP_WAIT_CHALLENGE;
- sm->leap_done = FALSE;
+ sm->leap_done = false;
return data;
}
@@ -77,14 +77,14 @@ static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (*pos != LEAP_VERSION) {
wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
"%d", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos++;
@@ -96,7 +96,7 @@ static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
"(challenge_len=%d reqDataLen=%lu)",
challenge_len, (unsigned long) wpabuf_len(reqData));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
challenge = pos;
@@ -119,7 +119,7 @@ static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
(!pwhash &&
nt_challenge_response(challenge, password, password_len, rpos))) {
wpa_printf(MSG_DEBUG, "EAP-LEAP: Failed to derive response");
- ret->ignore = TRUE;
+ ret->ignore = true;
wpabuf_free(resp);
return NULL;
}
@@ -153,7 +153,7 @@ static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
if (data->state != LEAP_WAIT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -170,7 +170,7 @@ static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
"for challenge");
wpabuf_free(resp);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
@@ -204,14 +204,14 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (*pos != LEAP_VERSION) {
wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
"%d", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos++;
@@ -223,7 +223,7 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
"(response_len=%d reqDataLen=%lu)",
response_len, (unsigned long) wpabuf_len(reqData));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -233,23 +233,23 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
if (pwhash) {
if (hash_nt_password_hash(password, pw_hash_hash)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
} else {
if (nt_password_hash(password, password_len, pw_hash) ||
hash_nt_password_hash(pw_hash, pw_hash_hash)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
if (challenge_response(data->ap_challenge, pw_hash_hash, expected)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
ret->methodState = METHOD_DONE;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
@@ -265,7 +265,7 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
/* LEAP is somewhat odd method since it sends EAP-Success in the middle
* of the authentication. Use special variable to transit EAP state
* machine to SUCCESS state. */
- sm->leap_done = TRUE;
+ sm->leap_done = true;
data->state = LEAP_DONE;
/* No more authentication messages expected; AP will send EAPOL-Key
@@ -286,7 +286,7 @@ static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
eap_sm_request_password(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -300,16 +300,16 @@ static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
if (wpabuf_len(reqData) < sizeof(*eap) ||
be_to_host16(eap->length) > wpabuf_len(reqData)) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
- ret->allowNotifications = TRUE;
+ ret->ignore = false;
+ ret->allowNotifications = true;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- sm->leap_done = FALSE;
+ sm->leap_done = false;
switch (eap->code) {
case EAP_CODE_REQUEST:
@@ -321,13 +321,13 @@ static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
default:
wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
"ignored", eap->code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
-static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_leap_data *data = priv;
return data->state == LEAP_DONE;
diff --git a/contrib/wpa/src/eap_peer/eap_md5.c b/contrib/wpa/src/eap_peer/eap_md5.c
index efae8deba85d..14ac5696eb2c 100644
--- a/contrib/wpa/src/eap_peer/eap_md5.c
+++ b/contrib/wpa/src/eap_peer/eap_md5.c
@@ -39,7 +39,7 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
eap_sm_request_password(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -47,7 +47,7 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
if (pos == NULL || len == 0) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
pos, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -60,10 +60,10 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
"(challenge_len=%lu len=%lu)",
(unsigned long) challenge_len, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
challenge = pos;
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
challenge, challenge_len);
@@ -71,7 +71,7 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -89,7 +89,7 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
if (chap_md5(id, password, password_len, challenge, challenge_len,
rpos)) {
wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
- ret->ignore = TRUE;
+ ret->ignore = true;
wpabuf_free(resp);
return NULL;
}
diff --git a/contrib/wpa/src/eap_peer/eap_methods.c b/contrib/wpa/src/eap_peer/eap_methods.c
index 9747954952a7..f2d29473685d 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.c
+++ b/contrib/wpa/src/eap_peer/eap_methods.c
@@ -27,7 +27,8 @@ static void eap_peer_method_free(struct eap_method *method);
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -47,7 +48,7 @@ const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_peer_get_type(const char *name, int *vendor)
+enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -70,7 +71,7 @@ EapType eap_peer_get_type(const char *name, int *vendor)
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_get_name(int vendor, EapType type)
+const char * eap_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
@@ -169,7 +170,7 @@ const struct eap_method * eap_peer_get_methods(size_t *count)
for (m = eap_methods; m; m = m->next)
c++;
-
+
*count = c;
return eap_methods;
}
@@ -279,7 +280,8 @@ int eap_peer_method_unload(struct eap_method *method)
* is not needed anymore.
*/
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
diff --git a/contrib/wpa/src/eap_peer/eap_methods.h b/contrib/wpa/src/eap_peer/eap_methods.h
index 09e08d3cfe3d..e94f3d75a426 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.h
+++ b/contrib/wpa/src/eap_peer/eap_methods.h
@@ -11,31 +11,33 @@
#include "eap_common/eap_defs.h"
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method);
const struct eap_method * eap_peer_get_methods(size_t *count);
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_peer_method_register(struct eap_method *method);
#ifdef IEEE8021X_EAPOL
-EapType eap_peer_get_type(const char *name, int *vendor);
-const char * eap_get_name(int vendor, EapType type);
+enum eap_type eap_peer_get_type(const char *name, int *vendor);
+const char * eap_get_name(int vendor, enum eap_type type);
size_t eap_get_names(char *buf, size_t buflen);
char ** eap_get_names_as_string_array(size_t *num);
void eap_peer_unregister_methods(void);
#else /* IEEE8021X_EAPOL */
-static inline EapType eap_peer_get_type(const char *name, int *vendor)
+static inline enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
*vendor = EAP_VENDOR_IETF;
return EAP_TYPE_NONE;
}
-static inline const char * eap_get_name(int vendor, EapType type)
+static inline const char * eap_get_name(int vendor, enum eap_type type)
{
return NULL;
}
diff --git a/contrib/wpa/src/eap_peer/eap_mschapv2.c b/contrib/wpa/src/eap_peer/eap_mschapv2.c
index 249baec88ebb..8ad4d18b3535 100644
--- a/contrib/wpa/src/eap_peer/eap_mschapv2.c
+++ b/contrib/wpa/src/eap_peer/eap_mschapv2.c
@@ -250,7 +250,7 @@ static struct wpabuf * eap_mschapv2_challenge(
if (req_len < sizeof(*req) + 1) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
"(len %lu)", (unsigned long) req_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = (const u8 *) (req + 1);
@@ -259,7 +259,7 @@ static struct wpabuf * eap_mschapv2_challenge(
if (challenge_len != MSCHAPV2_CHAL_LEN) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
"%lu", (unsigned long) challenge_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -267,7 +267,7 @@ static struct wpabuf * eap_mschapv2_challenge(
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
" packet: len=%lu challenge_len=%lu",
(unsigned long) len, (unsigned long) challenge_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -282,10 +282,10 @@ static struct wpabuf * eap_mschapv2_challenge(
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
pos, len);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
challenge);
@@ -377,7 +377,7 @@ static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
"buffer for success response");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -385,7 +385,7 @@ static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
data->success = 1;
if (data->prev_error == ERROR_PASSWD_EXPIRED)
@@ -531,10 +531,10 @@ static struct wpabuf * eap_mschapv2_change_password(
username = mschapv2_remove_domain(username, &username_len);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
ms_len = sizeof(*ms) + sizeof(*cp);
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
@@ -672,10 +672,10 @@ static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
os_free(buf);
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
data->passwd_change_version == 3) {
@@ -783,7 +783,7 @@ static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
u8 id;
if (eap_mschapv2_check_config(sm)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -800,13 +800,13 @@ static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
&len);
if (pos == NULL || len < sizeof(*ms) + 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
ms = (const struct eap_mschapv2_hdr *) pos;
if (eap_mschapv2_check_mslen(sm, len, ms)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -826,13 +826,13 @@ static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
default:
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
ms->op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
-static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->success && data->master_key_valid;
diff --git a/contrib/wpa/src/eap_peer/eap_otp.c b/contrib/wpa/src/eap_peer/eap_otp.c
index 0ab4c7907ab5..87615c6a6af1 100644
--- a/contrib/wpa/src/eap_peer/eap_otp.c
+++ b/contrib/wpa/src/eap_peer/eap_otp.c
@@ -36,7 +36,7 @@ static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
@@ -53,15 +53,15 @@ static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
eap_sm_request_otp(sm, (const char *) pos, len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len,
EAP_CODE_RESPONSE, eap_get_id(reqData));
diff --git a/contrib/wpa/src/eap_peer/eap_pax.c b/contrib/wpa/src/eap_peer/eap_pax.c
index 3cef1c8800a2..a641d44c17a6 100644
--- a/contrib/wpa/src/eap_peer/eap_pax.c
+++ b/contrib/wpa/src/eap_peer/eap_pax.c
@@ -127,14 +127,14 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
if (data->state != PAX_INIT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
"ignored");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -143,7 +143,7 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
if (left < 2 + EAP_PAX_RAND_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
"payload");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -152,7 +152,7 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
"length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -171,7 +171,7 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
@@ -180,7 +180,7 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
data->mk, data->ck, data->ick,
data->mid) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -243,14 +243,14 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
if (data->state != PAX_STD_2_SENT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
"ignored");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -259,7 +259,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
if (left < 2 + EAP_PAX_MAC_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
"payload");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -268,7 +268,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
"MAC_CK length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos += 2;
@@ -323,7 +323,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
data->state = PAX_DONE;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -343,7 +343,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len);
if (pos == NULL || len < sizeof(*req) + EAP_PAX_ICV_LEN) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
id = eap_get_id(reqData);
@@ -363,7 +363,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->mac_id, req->mac_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -371,7 +371,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->dh_group_id, req->dh_group_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -380,7 +380,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->public_key_id, req->public_key_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -388,21 +388,21 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
req->mac_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
req->dh_group_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
req->public_key_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -410,7 +410,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
/* TODO: add support for reassembling fragments */
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
"ignored packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -430,14 +430,14 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (req->op_code) {
case EAP_PAX_OP_STD_1:
@@ -449,19 +449,19 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
default:
wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
"op_code %d", req->op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return resp;
}
-static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == PAX_DONE;
diff --git a/contrib/wpa/src/eap_peer/eap_peap.c b/contrib/wpa/src/eap_peer/eap_peap.c
index 6453afe2fc57..12e30df295fc 100644
--- a/contrib/wpa/src/eap_peer/eap_peap.c
+++ b/contrib/wpa/src/eap_peer/eap_peap.c
@@ -137,7 +137,7 @@ static void * eap_peap_init(struct eap_sm *sm)
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- sm->peap_done = FALSE;
+ sm->peap_done = false;
data->peap_version = EAP_PEAP_VERSION;
data->force_peap_version = -1;
data->peap_outer_success = 2;
@@ -148,7 +148,7 @@ static void * eap_peap_init(struct eap_sm *sm)
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_peap_deinit(sm, data);
return NULL;
}
@@ -603,6 +603,8 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
u8 *pos;
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
+ int vendor;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-PEAP: too short "
@@ -666,13 +668,26 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
#endif /* EAP_TNC */
/* fall through */
default:
+ vendor = EAP_VENDOR_IETF;
+ method = *pos;
+
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE) {
size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor !=
- EAP_VENDOR_IETF ||
- data->phase2_types[i].method != *pos)
+ if (data->phase2_types[i].vendor != vendor ||
+ data->phase2_types[i].method != method)
continue;
data->phase2_type.vendor =
@@ -686,8 +701,9 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
break;
}
}
- if (*pos != data->phase2_type.method ||
- *pos == EAP_TYPE_NONE) {
+ if (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -787,6 +803,10 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (res)
return res;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
@@ -904,7 +924,7 @@ continue_req:
/* No EAP-Success expected for Phase 1 (outer,
* unencrypted auth), so force EAP state
* machine to SUCCESS state. */
- sm->peap_done = TRUE;
+ sm->peap_done = true;
}
} else {
/* FIX: ? */
@@ -914,7 +934,7 @@ continue_req:
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_MAY_CONT;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
/* Reply with EAP-Failure within the TLS channel to complete
* failure reporting. */
resp = wpabuf_alloc(sizeof(struct eap_hdr));
@@ -998,7 +1018,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
data->force_peap_version);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
@@ -1065,7 +1085,11 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- char *label;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
eap_peap_free_key(data);
@@ -1075,16 +1099,25 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
* PEAPv1 implementations seem to be using the old
* label, "client EAP encryption", instead. Use the old
* label by default, but allow it to be configured with
- * phase1 parameter peaplabel=1. */
- if (data->force_new_label)
+ * phase1 parameter peaplabel=1.
+ *
+ * When using TLS 1.3, draft-ietf-emu-tls-eap-types
+ * defines a new set of label and context parameters.
+ */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else if (data->force_new_label) {
label = "client PEAP encryption";
- else
+ } else {
label = "client EAP encryption";
+ }
wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
@@ -1150,7 +1183,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
if (res == 1) {
@@ -1163,7 +1196,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
@@ -1204,7 +1237,7 @@ static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
data->phase2_eap_started = 0;
data->resuming = 1;
data->reauth = 1;
- sm->peap_done = FALSE;
+ sm->peap_done = false;
return priv;
}
@@ -1229,7 +1262,7 @@ static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
}
-static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->key_data != NULL && data->phase2_success;
diff --git a/contrib/wpa/src/eap_peer/eap_psk.c b/contrib/wpa/src/eap_peer/eap_psk.c
index eea9430d2406..4997e6a564c9 100644
--- a/contrib/wpa/src/eap_peer/eap_psk.c
+++ b/contrib/wpa/src/eap_peer/eap_psk.c
@@ -100,7 +100,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
"length (%lu; expected %lu or more)",
(unsigned long) len,
(unsigned long) sizeof(*hdr1));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
@@ -120,7 +120,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
"ID_S (len=%lu)", (unsigned long) data->id_s_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
@@ -128,7 +128,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -198,7 +198,7 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
"length (%lu; expected %lu or more)",
(unsigned long) len,
(unsigned long) sizeof(*hdr3));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
left = len - sizeof(*hdr3);
@@ -220,7 +220,7 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
"third message (len=%lu, expected 21)",
(unsigned long) left);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -377,14 +377,14 @@ static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (data->state) {
case PSK_INIT:
@@ -396,19 +396,19 @@ static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
case PSK_DONE:
wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
"unexpected message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return resp;
}
-static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == PSK_DONE;
diff --git a/contrib/wpa/src/eap_peer/eap_pwd.c b/contrib/wpa/src/eap_peer/eap_pwd.c
index 54f102a3b043..605feb24f851 100644
--- a/contrib/wpa/src/eap_peer/eap_pwd.c
+++ b/contrib/wpa/src/eap_peer/eap_pwd.c
@@ -257,13 +257,13 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_pwd_id *id;
if (data->state != PWD_ID_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
eap_pwd_state(data, FAILURE);
return;
}
if (payload_len < sizeof(struct eap_pwd_id)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
eap_pwd_state(data, FAILURE);
return;
}
@@ -369,14 +369,14 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
int res;
if (data->state != PWD_Commit_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
if (!data->grp) {
wpa_printf(MSG_DEBUG,
"EAP-PWD (client): uninitialized EAP-pwd group");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
@@ -696,7 +696,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
size_t prime_len = 0, order_len = 0;
if (data->state != PWD_Confirm_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
@@ -878,14 +878,14 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and "
"len is %d",
pos == NULL ? "NULL" : "not NULL", (int) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
lm_exch = *pos;
pos++; /* skip over the bits and the exch */
@@ -951,7 +951,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
if (len < 2) {
wpa_printf(MSG_DEBUG,
"EAP-pwd: Frame too short to contain Total-Length field");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
tot_len = WPA_GET_BE16(pos);
@@ -962,7 +962,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
if (data->inbuf) {
wpa_printf(MSG_DEBUG,
"EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->inbuf = wpabuf_alloc(tot_len);
@@ -1107,7 +1107,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
}
-static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
+static bool eap_pwd_key_available(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_sake.c b/contrib/wpa/src/eap_peer/eap_sake.c
index 255241f6d5aa..39c195dfdb53 100644
--- a/contrib/wpa/src/eap_peer/eap_sake.c
+++ b/contrib/wpa/src/eap_peer/eap_sake.c
@@ -148,7 +148,7 @@ static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
struct wpabuf *resp;
if (data->state != IDENTITY) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -195,7 +195,7 @@ static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
if (data->state != IDENTITY && data->state != CHALLENGE) {
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
"in unexpected state (%d)", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == IDENTITY)
@@ -296,7 +296,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
u8 *rpos;
if (data->state != CONFIRM) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -320,7 +320,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
eap_sake_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
return eap_sake_build_msg(data, id, 0,
EAP_SAKE_SUBTYPE_AUTH_REJECT);
@@ -330,7 +330,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
eap_sake_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
"Response/Auth-Reject");
return eap_sake_build_msg(data, id, 0,
@@ -361,7 +361,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
eap_sake_state(data, SUCCESS);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -380,7 +380,7 @@ static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -399,16 +399,16 @@ static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
if (data->session_id_set && data->session_id != session_id) {
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
session_id, data->session_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->session_id = session_id;
data->session_id_set = 1;
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (subtype) {
case EAP_SAKE_SUBTYPE_IDENTITY:
@@ -426,18 +426,18 @@ static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
default:
wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
"unknown subtype %d", subtype);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE)
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
-static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_sim.c b/contrib/wpa/src/eap_peer/eap_sim.c
index 2ea4efd07c6d..09866277d6a8 100644
--- a/contrib/wpa/src/eap_peer/eap_sim.c
+++ b/contrib/wpa/src/eap_peer/eap_sim.c
@@ -44,7 +44,7 @@ struct eap_sim_data {
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
+ CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
int use_pseudonym;
@@ -58,6 +58,8 @@ static const char * eap_sim_state_txt(int state)
switch (state) {
case CONTINUE:
return "CONTINUE";
+ case START_DONE:
+ return "START_DONE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
case SUCCESS:
@@ -486,6 +488,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
+ struct wpabuf *resp;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -517,6 +520,12 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
+ identity, identity_len);
+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+ identity, identity_len);
+ }
if (!data->reauth) {
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
@@ -528,14 +537,10 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
data->selected_version, NULL, 0);
}
- if (identity) {
- wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
- identity, identity_len);
- eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
- identity, identity_len);
- }
-
- return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
+ resp = eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
+ if (resp)
+ eap_sim_state(data, START_DONE);
+ return resp;
}
@@ -721,6 +726,13 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
int res;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
+ if (data->state != START_DONE) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Unexpected Challenge in state %s",
+ eap_sim_state_txt(data->state));
+ return eap_sim_client_error(data, id,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
data->reauth = 0;
if (!attr->mac || !attr->rand) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
@@ -1091,23 +1103,23 @@ static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
eap_sm_request_identity(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
if (pos == NULL || len < 3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
req = wpabuf_head(reqData);
id = req->identifier;
len = be_to_host16(req->length);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
@@ -1160,14 +1172,14 @@ done:
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return res;
}
-static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->pseudonym || data->reauth_id;
@@ -1218,7 +1230,7 @@ static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
}
-static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_teap.c b/contrib/wpa/src/eap_peer/eap_teap.c
index 07ecbd447b1e..e8cc7844ce5f 100644
--- a/contrib/wpa/src/eap_peer/eap_teap.c
+++ b/contrib/wpa/src/eap_peer/eap_teap.c
@@ -35,6 +35,7 @@ struct eap_teap_data {
void *phase2_priv;
int phase2_success;
int inner_method_done;
+ int iresult_verified;
int result_success_done;
int on_tx_completion;
@@ -168,7 +169,7 @@ static void * eap_teap_init(struct eap_sm *sm)
eap_teap_parse_phase1(data, config->phase1);
if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
- !config->ca_cert && !config->ca_path) {
+ !config->cert.ca_cert && !config->cert.ca_path) {
/* Prevent PAC provisioning without mutual authentication
* (either by validating server certificate or by suitable
* inner EAP method). */
@@ -179,7 +180,7 @@ static void * eap_teap_init(struct eap_sm *sm)
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_teap_deinit(sm, data);
return NULL;
}
@@ -277,8 +278,10 @@ static int eap_teap_derive_msk(struct eap_teap_data *data)
{
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, data->key_data) < 0 ||
- eap_teap_derive_eap_emsk(data->simck_msk, data->emsk) < 0)
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ data->key_data) < 0 ||
+ eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ data->emsk) < 0)
return -1;
data->success = 1;
return 0;
@@ -309,6 +312,7 @@ static int eap_teap_init_phase2_method(struct eap_sm *sm,
struct eap_teap_data *data)
{
data->inner_method_done = 0;
+ data->iresult_verified = 0;
data->phase2_method =
eap_peer_get_eap_method(data->phase2_type.vendor,
data->phase2_type.method);
@@ -323,7 +327,8 @@ static int eap_teap_init_phase2_method(struct eap_sm *sm,
}
-static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
+static int eap_teap_select_phase2_method(struct eap_teap_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
@@ -331,15 +336,15 @@ static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
* completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
if (data->anon_provisioning &&
- !eap_teap_allowed_anon_prov_phase2_method(type)) {
+ !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: EAP type %u not allowed during unauthenticated provisioning",
- type);
+ "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG,
@@ -351,7 +356,7 @@ static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -364,13 +369,31 @@ static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
}
+static void eap_teap_deinit_inner_eap(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (!data->phase2_priv || !data->phase2_method)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
+}
+
+
static int eap_teap_phase2_request(struct eap_sm *sm,
struct eap_teap_data *data,
struct eap_method_ret *ret,
@@ -382,6 +405,8 @@ static int eap_teap_phase2_request(struct eap_sm *sm,
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO,
@@ -390,26 +415,33 @@ static int eap_teap_phase2_request(struct eap_sm *sm,
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
+ eap_teap_deinit_inner_eap(sm, data);
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
- data->phase2_method->deinit(sm, data->phase2_priv);
- data->phase2_method = NULL;
- data->phase2_priv = NULL;
- data->phase2_type.vendor = EAP_VENDOR_IETF;
- data->phase2_type.method = EAP_TYPE_NONE;
- }
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method))
+ eap_teap_deinit_inner_eap(sm, data);
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_teap_select_phase2_method(data, *pos) < 0) {
+ eap_teap_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -420,8 +452,8 @@ static int eap_teap_phase2_request(struct eap_sm *sm,
if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) ||
!data->phase2_method) {
wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to initialize Phase 2 EAP method %d",
- *pos);
+ "EAP-TEAP: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
@@ -436,7 +468,8 @@ static int eap_teap_phase2_request(struct eap_sm *sm,
if (!(*resp) ||
(iret.methodState == METHOD_DONE &&
iret.decision == DECISION_FAIL)) {
- ret->methodState = METHOD_DONE;
+ /* Wait for protected indication of failure */
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
} else if ((iret.methodState == METHOD_DONE ||
iret.methodState == METHOD_MAY_CONT) &&
@@ -500,10 +533,23 @@ static struct wpabuf * eap_teap_tlv_pac_ack(void)
}
+static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm,
+ struct wpabuf *msg)
+{
+ struct wpabuf *tlv;
+
+ tlv = eap_teap_tlv_identity_type(sm->use_machine_cred ?
+ TEAP_IDENTITY_TYPE_MACHINE :
+ TEAP_IDENTITY_TYPE_USER);
+ return wpabuf_concat(msg, tlv);
+}
+
+
static struct wpabuf * eap_teap_process_eap_payload_tlv(
struct eap_sm *sm, struct eap_teap_data *data,
struct eap_method_ret *ret,
- u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
+ u8 *eap_payload_tlv, size_t eap_payload_tlv_len,
+ enum teap_identity_types req_id_type)
{
struct eap_hdr *hdr;
struct wpabuf *resp = NULL;
@@ -535,13 +581,18 @@ static struct wpabuf * eap_teap_process_eap_payload_tlv(
return NULL;
}
- return eap_teap_tlv_eap_payload(resp);
+ resp = eap_teap_tlv_eap_payload(resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
+
+ return resp;
}
static struct wpabuf * eap_teap_process_basic_auth_req(
struct eap_sm *sm, struct eap_teap_data *data,
- u8 *basic_auth_req, size_t basic_auth_req_len)
+ u8 *basic_auth_req, size_t basic_auth_req_len,
+ enum teap_identity_types req_id_type)
{
const u8 *identity, *password;
size_t identity_len, password_len, plen;
@@ -571,6 +622,8 @@ static struct wpabuf * eap_teap_process_basic_auth_req(
wpabuf_put_data(resp, password, password_len);
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp",
resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
/* Assume this succeeds so that Result TLV(Success) from the server can
* be used to terminate TEAP. */
@@ -680,7 +733,8 @@ static int eap_teap_get_cmk(struct eap_sm *sm, struct eap_teap_data *data,
data->simck_idx + 1);
if (!data->phase2_method)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -712,7 +766,8 @@ static int eap_teap_get_cmk(struct eap_sm *sm, struct eap_teap_data *data,
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, cmk_msk,
data->simck_emsk, cmk_emsk);
@@ -1189,6 +1244,7 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
struct eap_teap_tlv_parse tlv;
int failed = 0;
enum teap_error_codes error = 0;
+ int iresult_added = 0;
if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) {
/* Parsing failed - no response available */
@@ -1212,14 +1268,21 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
goto send_resp;
}
- if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
- (!data->result_success_done &&
- tlv.result == TEAP_STATUS_SUCCESS)) &&
- !tlv.crypto_binding) {
- /* Result TLV or Intermediate-Result TLV indicating success,
- * but no Crypto-Binding TLV */
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Intermediate-Result TLV indicating success, but no
+ * Crypto-Binding TLV */
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Result TLV or Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ "EAP-TEAP: Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (!data->iresult_verified && !data->result_success_done &&
+ tlv.result == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Result TLV indicating success, but no Crypto-Binding TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Result TLV indicating success, but no Crypto-Binding TLV");
failed = 1;
error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
goto done;
@@ -1235,17 +1298,45 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
goto done;
}
+ if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ sm->use_machine_cred = config && config->machine_identity &&
+ config->machine_identity_len;
+ } else if (tlv.identity_type) {
+ sm->use_machine_cred = 0;
+ }
+ if (tlv.identity_type) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ os_free(data->phase2_types);
+ data->phase2_types = NULL;
+ data->num_phase2_types = 0;
+ if (config &&
+ eap_peer_select_phase2_methods(config, "auth=",
+ &data->phase2_types,
+ &data->num_phase2_types,
+ sm->use_machine_cred) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to update Phase 2 EAP types");
+ failed = 1;
+ goto done;
+ }
+ }
+
if (tlv.basic_auth_req) {
tmp = eap_teap_process_basic_auth_req(sm, data,
tlv.basic_auth_req,
- tlv.basic_auth_req_len);
+ tlv.basic_auth_req_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
} else if (tlv.eap_payload_tlv) {
tmp = eap_teap_process_eap_payload_tlv(sm, data, ret,
tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
if (!tmp)
failed = 1;
resp = wpabuf_concat(resp, tmp);
@@ -1258,6 +1349,7 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
resp = wpabuf_concat(resp, tmp);
if (tlv.iresult == TEAP_STATUS_FAILURE)
failed = 1;
+ iresult_added = 1;
}
}
@@ -1281,8 +1373,10 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
resp = wpabuf_concat(resp, tmp);
if (tlv.result == TEAP_STATUS_SUCCESS && !failed)
data->result_success_done = 1;
- if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed)
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) {
data->inner_method_done = 0;
+ data->iresult_verified = 1;
+ }
}
}
@@ -1294,6 +1388,15 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
"EAP-TEAP: PAC used - server may decide to skip inner authentication");
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
+ } else if (data->result_success_done &&
+ tls_connection_get_own_cert_used(data->ssl.conn) &&
+ eap_teap_derive_msk(data) == 0) {
+ /* Assume the server might accept authentication without going
+ * through inner authentication. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Client certificate used - server may decide to skip inner authentication");
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
}
if (tlv.pac) {
@@ -1316,6 +1419,7 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
data->phase2_method->vendor == 0 &&
eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
eap_teap_allowed_anon_prov_phase2_method(
+ data->phase2_method->vendor,
data->phase2_method->method))) &&
(tlv.iresult == TEAP_STATUS_SUCCESS ||
tlv.result == TEAP_STATUS_SUCCESS)) {
@@ -1344,9 +1448,17 @@ done:
tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
resp = wpabuf_concat(tmp, resp);
}
+ if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.iresult == TEAP_STATUS_FAILURE) && !iresult_added) {
+ tmp = eap_teap_tlv_result((!failed && data->phase2_success) ?
+ TEAP_STATUS_SUCCESS :
+ TEAP_STATUS_FAILURE, 1);
+ resp = wpabuf_concat(tmp, resp);
+ }
if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed &&
- tlv.crypto_binding && data->phase2_success) {
+ (tlv.crypto_binding || data->iresult_verified) &&
+ data->phase2_success) {
/* Successfully completed Phase 2 */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Authentication completed successfully");
@@ -1882,7 +1994,7 @@ static struct wpabuf * eap_teap_process(struct eap_sm *sm, void *priv,
#if 0 /* TODO */
-static Boolean eap_teap_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_teap_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_teap_data *data = priv;
@@ -1915,6 +2027,7 @@ static void * eap_teap_init_for_reauth(struct eap_sm *sm, void *priv)
data->phase2_success = 0;
data->inner_method_done = 0;
data->result_success_done = 0;
+ data->iresult_verified = 0;
data->done_on_tx_completion = 0;
data->resuming = 1;
data->provisioning = 0;
@@ -1944,7 +2057,7 @@ static int eap_teap_get_status(struct eap_sm *sm, void *priv, char *buf,
}
-static Boolean eap_teap_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_teap_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_teap_data *data = priv;
diff --git a/contrib/wpa/src/eap_peer/eap_tls.c b/contrib/wpa/src/eap_peer/eap_tls.c
index 15d60d710094..0d479f1c298c 100644
--- a/contrib/wpa/src/eap_peer/eap_tls.c
+++ b/contrib/wpa/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,10 +33,17 @@ static void * eap_tls_init(struct eap_sm *sm)
{
struct eap_tls_data *data;
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL ||
- ((sm->init_phase2 ? config->private_key2 : config->private_key)
- == NULL &&
- (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+ struct eap_peer_cert_config *cert;
+
+ if (!config)
+ return NULL;
+ if (!sm->init_phase2)
+ cert = &config->cert;
+ else if (sm->use_machine_cred)
+ cert = &config->machine_cert;
+ else
+ cert = &config->phase2_cert;
+ if (!cert->private_key && cert->engine == 0) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@@ -51,17 +58,16 @@ static void * eap_tls_init(struct eap_sm *sm)
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
- if (config->engine) {
+ if (cert->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
eap_sm_request_pin(sm);
- sm->ignore = TRUE;
- } else if (config->private_key && !config->private_key_passwd)
- {
+ sm->ignore = true;
+ } else if (cert->private_key && !cert->private_key_passwd) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
eap_sm_request_passphrase(sm);
- sm->ignore = TRUE;
+ sm->ignore = true;
}
return NULL;
}
@@ -296,15 +302,11 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
return NULL;
}
- if (res == 2) {
- /* Application data included in the handshake message (used by
- * EAP-TLS 1.3 to indicate conclusion of the exchange). */
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Received Application Data",
- resp);
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Remaining tls_out data",
- data->ssl.tls_out);
+ /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 &&
+ *wpabuf_head_u8(resp) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message");
eap_peer_tls_reset_output(&data->ssl);
- /* Send an ACK to allow the server to complete exchange */
res = 1;
}
@@ -320,7 +322,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return tls_connection_established(data->ssl_ctx, data->ssl.conn);
@@ -358,7 +360,7 @@ static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
}
-static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->key_data != NULL;
diff --git a/contrib/wpa/src/eap_peer/eap_tls_common.c b/contrib/wpa/src/eap_peer/eap_tls_common.c
index 7e0690c06bf4..c1837db06221 100644
--- a/contrib/wpa/src/eap_peer/eap_tls_common.c
+++ b/contrib/wpa/src/eap_peer/eap_tls_common.c
@@ -16,7 +16,7 @@
#include "eap_config.h"
-static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+static struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -105,8 +105,8 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
}
-static void eap_tls_params_from_conf1(struct tls_connection_params *params,
- struct eap_peer_config *config)
+static void eap_tls_cert_params_from_conf(struct tls_connection_params *params,
+ struct eap_peer_cert_config *config)
{
params->ca_cert = config->ca_cert;
params->ca_path = config->ca_path;
@@ -125,6 +125,19 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
params->key_id = config->key_id;
params->cert_id = config->cert_id;
params->ca_cert_id = config->ca_cert_id;
+ if (config->ocsp)
+ params->flags |= TLS_CONN_REQUEST_OCSP;
+ if (config->ocsp >= 2)
+ params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
+}
+
+
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->cert);
eap_tls_params_flags(params, config->phase1);
}
@@ -132,27 +145,19 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = config->ca_cert2;
- params->ca_path = config->ca_path2;
- params->client_cert = config->client_cert2;
- params->private_key = config->private_key2;
- params->private_key_passwd = config->private_key2_passwd;
- params->dh_file = config->dh_file2;
- params->subject_match = config->subject_match2;
- params->altsubject_match = config->altsubject_match2;
- params->check_cert_subject = config->check_cert_subject2;
- params->suffix_match = config->domain_suffix_match2;
- params->domain_match = config->domain_match2;
- params->engine = config->engine2;
- params->engine_id = config->engine2_id;
- params->pin = config->pin2;
- params->key_id = config->key2_id;
- params->cert_id = config->cert2_id;
- params->ca_cert_id = config->ca_cert2_id;
+ eap_tls_cert_params_from_conf(params, &config->phase2_cert);
eap_tls_params_flags(params, config->phase2);
}
+static void eap_tls_params_from_conf2m(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->machine_cert);
+ eap_tls_params_flags(params, config->machine_phase2);
+}
+
+
static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_ssl_data *data,
struct tls_connection_params *params,
@@ -199,7 +204,10 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
- if (phase2) {
+ if (phase2 && sm->use_machine_cred) {
+ wpa_printf(MSG_DEBUG, "TLS: using machine config options");
+ eap_tls_params_from_conf2m(params, config);
+ } else if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
} else {
@@ -242,12 +250,6 @@ static int eap_tls_init_connection(struct eap_sm *sm,
{
int res;
- if (config->ocsp)
- params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp >= 2)
- params->flags |= TLS_CONN_REQUIRE_OCSP;
- if (config->ocsp == 3)
- params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -264,15 +266,15 @@ static int eap_tls_init_connection(struct eap_sm *sm,
*/
wpa_printf(MSG_INFO,
"TLS: Bad PIN provided, requesting a new one");
- os_free(config->pin);
- config->pin = NULL;
+ os_free(config->cert.pin);
+ config->cert.pin = NULL;
eap_sm_request_pin(sm);
- sm->ignore = TRUE;
+ sm->ignore = true;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
wpa_printf(MSG_INFO, "TLS: Failed to initialize engine");
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
- sm->ignore = TRUE;
+ sm->ignore = true;
}
if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
@@ -411,9 +413,9 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct tls_random keys;
u8 *out;
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
- const u8 context[] = { EAP_TYPE_TLS };
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
@@ -619,7 +621,8 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
* @out_data: Buffer for returning the allocated output buffer
* Returns: ret (0 or 1) on success, -1 on failure
*/
-static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+static int eap_tls_process_output(struct eap_ssl_data *data,
+ enum eap_type eap_type,
int peap_version, u8 id, int ret,
struct wpabuf **out_data)
{
@@ -717,7 +720,7 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
* the tunneled data is used.
*/
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -809,7 +812,7 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
* @peap_version: Version number for EAP-PEAP/TTLS
* Returns: Pointer to the allocated ACK frame or %NULL on failure
*/
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version)
{
struct wpabuf *resp;
@@ -899,7 +902,7 @@ int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
*/
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags)
@@ -910,7 +913,7 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
if (tls_get_errors(data->ssl_ctx)) {
wpa_printf(MSG_INFO, "SSL: TLS errors detected");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -926,14 +929,14 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
&left);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (left == 0) {
wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
"octet included");
if (!sm->workaround) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -951,7 +954,7 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
if (left < 4) {
wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
"length");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
tls_msg_len = WPA_GET_BE32(pos);
@@ -970,15 +973,15 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
"bytes) smaller than this fragment (%d "
"bytes)", (int) tls_msg_len, (int) left);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
*len = left;
return pos;
@@ -1056,7 +1059,7 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
* Returns: 0 on success, -1 on failure
*/
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -1092,17 +1095,21 @@ int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types)
+ size_t *num_types, int use_machine_cred)
{
char *start, *pos, *buf;
struct eap_method_type *methods = NULL, *_methods;
u32 method;
size_t num_methods = 0, prefix_len;
+ const char *phase2;
- if (config == NULL || config->phase2 == NULL)
+ if (!config)
+ goto get_defaults;
+ phase2 = use_machine_cred ? config->machine_phase2 : config->phase2;
+ if (!phase2)
goto get_defaults;
- start = buf = os_strdup(config->phase2);
+ start = buf = os_strdup(phase2);
if (buf == NULL)
return -1;
diff --git a/contrib/wpa/src/eap_peer/eap_tls_common.h b/contrib/wpa/src/eap_peer/eap_tls_common.h
index d96eff1c8b82..183b7de00ae5 100644
--- a/contrib/wpa/src/eap_peer/eap_tls_common.h
+++ b/contrib/wpa/src/eap_peer/eap_tls_common.h
@@ -107,17 +107,17 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data);
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version);
int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
char *buf, size_t buflen, int verbose);
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags);
@@ -127,13 +127,13 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
const struct wpabuf *in_data,
struct wpabuf **in_decrypted);
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data);
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types);
+ size_t *num_types, int use_machine_cred);
int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
struct eap_hdr *hdr, struct wpabuf **resp);
diff --git a/contrib/wpa/src/eap_peer/eap_tnc.c b/contrib/wpa/src/eap_peer/eap_tnc.c
index 726221e6b69c..af177736498a 100644
--- a/contrib/wpa/src/eap_peer/eap_tnc.c
+++ b/contrib/wpa/src/eap_peer/eap_tnc.c
@@ -92,9 +92,9 @@ static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
u8 flags;
size_t send_len, plen;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = EAP_TNC_VERSION;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -174,7 +174,7 @@ static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
"fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -184,7 +184,7 @@ static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpabuf_put_data(data->in_buf, buf, len);
@@ -219,7 +219,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
pos, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -235,14 +235,14 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
flags & EAP_TNC_VERSION_MASK);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
if (end - pos < 4) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE32(pos);
@@ -253,7 +253,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -265,7 +265,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
if (len > 1) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
"WAIT_FRAG_ACK state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
@@ -274,10 +274,10 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
}
if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
return eap_tnc_process_fragment(data, ret, id, flags,
message_length, pos,
@@ -294,7 +294,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
if (!(flags & EAP_TNC_FLAGS_START)) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
"start flag in the first message");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
}
@@ -307,7 +307,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
if (flags & EAP_TNC_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
"flag again");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
}
@@ -316,7 +316,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
wpabuf_len(data->in_buf));
switch (res) {
case TNCCS_PROCESS_ERROR:
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
case TNCCS_RECOMMENDATION_ERROR:
@@ -345,10 +345,10 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
wpabuf_free(data->in_buf);
data->in_buf = NULL;
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
diff --git a/contrib/wpa/src/eap_peer/eap_ttls.c b/contrib/wpa/src/eap_peer/eap_ttls.c
index 1c8dbe2b4331..c4019154d955 100644
--- a/contrib/wpa/src/eap_peer/eap_ttls.c
+++ b/contrib/wpa/src/eap_peer/eap_ttls.c
@@ -146,8 +146,8 @@ static void * eap_ttls_init(struct eap_sm *sm)
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
if (eap_peer_select_phase2_methods(config, "autheap=",
&data->phase2_eap_types,
- &data->num_phase2_eap_types)
- < 0) {
+ &data->num_phase2_eap_types,
+ 0) < 0) {
eap_ttls_deinit(sm, data);
return NULL;
}
@@ -268,10 +268,22 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eap_ttls_free_key(data);
- data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
- NULL, 0,
+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (!data->key_data) {
@@ -311,11 +323,11 @@ static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
- u8 method)
+ int vendor, enum eap_type method)
{
size_t i;
for (i = 0; i < data->num_phase2_eap_types; i++) {
- if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_eap_types[i].vendor != vendor ||
data->phase2_eap_types[i].method != method)
continue;
@@ -362,17 +374,19 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *hdr, size_t len,
- u8 method, struct wpabuf **resp)
+ int vendor, enum eap_type method,
+ struct wpabuf **resp)
{
#ifdef EAP_TNC
if (data->tnc_started && data->phase2_method &&
- data->phase2_priv && method == EAP_TYPE_TNC &&
+ data->phase2_priv &&
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC &&
data->phase2_eap_type.method == EAP_TYPE_TNC)
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
resp);
if (data->ready_for_tnc && !data->tnc_started &&
- method == EAP_TYPE_TNC) {
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
"EAP method");
data->tnc_started = 1;
@@ -386,7 +400,7 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
return -1;
}
- data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_eap_type.vendor = vendor;
data->phase2_eap_type.method = method;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
"Phase 2 EAP vendor %d method %d (TNC)",
@@ -400,10 +414,11 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
data->phase2_eap_type.method == EAP_TYPE_NONE)
- eap_ttls_phase2_select_eap_method(data, method);
+ eap_ttls_phase2_select_eap_method(data, vendor, method);
- if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
- {
+ if (vendor != data->phase2_eap_type.vendor ||
+ method != data->phase2_eap_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
data->num_phase2_eap_types,
hdr, resp))
@@ -412,8 +427,7 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_peer_get_eap_method(
- EAP_VENDOR_IETF, method);
+ data->phase2_method = eap_peer_get_eap_method(vendor, method);
if (data->phase2_method) {
sm->init_phase2 = 1;
data->phase2_priv = data->phase2_method->init(sm);
@@ -421,8 +435,9 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
- "Phase 2 EAP method %d", method);
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
return -1;
}
@@ -451,9 +466,23 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
case EAP_TYPE_IDENTITY:
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
break;
+ case EAP_TYPE_EXPANDED:
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
+ WPA_GET_BE24(pos + 1),
+ WPA_GET_BE32(pos + 4),
+ resp) < 0)
+ return -1;
+ break;
default:
if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
- *pos, resp) < 0)
+ EAP_VENDOR_IETF, *pos,
+ resp) < 0)
return -1;
break;
}
@@ -1424,6 +1453,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
data->phase2_start) {
+start:
return eap_ttls_phase2_start(sm, data, ret, identifier,
out_data);
}
@@ -1438,6 +1468,20 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (retval)
goto done;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ goto start;
+ }
+
+ /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 &&
+ *wpabuf_head_u8(in_decrypted) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: ACKing EAP-TLS Commitment Message");
+ eap_peer_tls_reset_output(&data->ssl);
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
data->phase2_start = 0;
@@ -1561,7 +1605,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
struct eap_method_ret *ret)
{
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1656,7 +1700,7 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
@@ -1747,7 +1791,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
}
-static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->key_data != NULL && data->phase2_success;
diff --git a/contrib/wpa/src/eap_peer/eap_vendor_test.c b/contrib/wpa/src/eap_peer/eap_vendor_test.c
index 16e3c39563b7..431f44b65bbf 100644
--- a/contrib/wpa/src/eap_peer/eap_vendor_test.c
+++ b/contrib/wpa/src/eap_peer/eap_vendor_test.c
@@ -75,28 +75,28 @@ static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == INIT && *pos != 1) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"%d in INIT state", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == CONFIRM && *pos != 3) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"%d in CONFIRM state", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"in SUCCESS state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -105,17 +105,17 @@ static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
data->first_try = 0;
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
"pending request");
- ret->ignore = TRUE;
+ ret->ignore = true;
eloop_register_timeout(1, 0, eap_vendor_ready, sm,
NULL);
return NULL;
}
}
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -138,7 +138,7 @@ static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_peer/eap_wsc.c b/contrib/wpa/src/eap_peer/eap_wsc.c
index 92d5a0235130..a1e7bff196c6 100644
--- a/contrib/wpa/src/eap_peer/eap_wsc.c
+++ b/contrib/wpa/src/eap_peer/eap_wsc.c
@@ -304,9 +304,9 @@ static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,
u8 flags;
size_t send_len, plen;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = 0;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -400,7 +400,7 @@ static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
"fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -410,7 +410,7 @@ static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->in_op_code = op_code;
@@ -441,7 +441,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
&len);
if (pos == NULL || len < 2) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -455,7 +455,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
if (flags & WSC_FLAGS_LF) {
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE16(pos);
@@ -464,7 +464,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -477,7 +477,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
if (op_code != WSC_FRAG_ACK) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
"in WAIT_FRAG_ACK state", op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
@@ -489,7 +489,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
op_code != WSC_Done && op_code != WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -497,7 +497,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
if (op_code != WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
"in WAIT_START state", op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
@@ -507,13 +507,13 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
} else if (op_code == WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->in_buf &&
eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
diff --git a/contrib/wpa/src/eap_peer/ikev2.c b/contrib/wpa/src/eap_peer/ikev2.c
index 7bd97b1b997e..c2e6c5df5e9e 100644
--- a/contrib/wpa/src/eap_peer/ikev2.c
+++ b/contrib/wpa/src/eap_peer/ikev2.c
@@ -201,7 +201,8 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
const u8 *pos, const u8 *end)
{
const u8 *pend, *ppos;
- int proposal_len, i;
+ int proposal_len;
+ unsigned int i, num;
const struct ikev2_proposal *p;
if (end - pos < (int) sizeof(*p)) {
@@ -269,12 +270,13 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
return -1;
}
- if (p->num_transforms == 0) {
+ num = p->num_transforms;
+ if (num == 0 || num > 255) {
wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
return -1;
}
- for (i = 0; i < (int) p->num_transforms; i++) {
+ for (i = 0; i < num; i++) {
int tlen = ikev2_parse_transform(prop, ppos, pend);
if (tlen < 0)
return -1;
@@ -411,7 +413,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data,
wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
data->i_dh_public);
-
+
return 0;
}
diff --git a/contrib/wpa/src/eap_peer/tncc.c b/contrib/wpa/src/eap_peer/tncc.c
index a9bafe2886c0..c460980999db 100644
--- a/contrib/wpa/src/eap_peer/tncc.c
+++ b/contrib/wpa/src/eap_peer/tncc.c
@@ -144,7 +144,7 @@ static TNC_Result TNC_TNCC_SendMessage(
TNC_MessageType messageType)
{
struct tnc_if_imc *imc;
- unsigned char *b64;
+ char *b64;
size_t b64len;
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
@@ -629,8 +629,7 @@ static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
return NULL;
*pos2 = '\0';
- decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
- decoded_len);
+ decoded = base64_decode(pos, os_strlen(pos), decoded_len);
*pos2 = '<';
if (decoded == NULL) {
wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
diff --git a/contrib/wpa/src/eap_server/Makefile b/contrib/wpa/src/eap_server/Makefile
new file mode 100644
index 000000000000..cc9b76d619a1
--- /dev/null
+++ b/contrib/wpa/src/eap_server/Makefile
@@ -0,0 +1,8 @@
+CFLAGS += -DCONFIG_HS20
+
+LIB_OBJS= \
+ eap_server.o \
+ eap_server_identity.o \
+ eap_server_methods.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/eap_server/eap.h b/contrib/wpa/src/eap_server/eap.h
index a9cf5c97bee7..61032cc016bc 100644
--- a/contrib/wpa/src/eap_server/eap.h
+++ b/contrib/wpa/src/eap_server/eap.h
@@ -45,43 +45,43 @@ struct eap_user {
struct eap_eapol_interface {
/* Lower layer to full authenticator variables */
- Boolean eapResp; /* shared with EAPOL Backend Authentication */
+ bool eapResp; /* shared with EAPOL Backend Authentication */
struct wpabuf *eapRespData;
- Boolean portEnabled;
+ bool portEnabled;
int retransWhile;
- Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
+ bool eapRestart; /* shared with EAPOL Authenticator PAE */
int eapSRTT;
int eapRTTVAR;
/* Full authenticator to lower layer variables */
- Boolean eapReq; /* shared with EAPOL Backend Authentication */
- Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
- Boolean eapSuccess;
- Boolean eapFail;
- Boolean eapTimeout;
+ bool eapReq; /* shared with EAPOL Backend Authentication */
+ bool eapNoReq; /* shared with EAPOL Backend Authentication */
+ bool eapSuccess;
+ bool eapFail;
+ bool eapTimeout;
struct wpabuf *eapReqData;
u8 *eapKeyData;
size_t eapKeyDataLen;
u8 *eapSessionId;
size_t eapSessionIdLen;
- Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
+ bool eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
/* AAA interface to full authenticator variables */
- Boolean aaaEapReq;
- Boolean aaaEapNoReq;
- Boolean aaaSuccess;
- Boolean aaaFail;
+ bool aaaEapReq;
+ bool aaaEapNoReq;
+ bool aaaSuccess;
+ bool aaaFail;
struct wpabuf *aaaEapReqData;
u8 *aaaEapKeyData;
size_t aaaEapKeyDataLen;
- Boolean aaaEapKeyAvailable;
+ bool aaaEapKeyAvailable;
int aaaMethodTimeout;
/* Full authenticator to AAA interface variables */
- Boolean aaaEapResp;
+ bool aaaEapResp;
struct wpabuf *aaaEapRespData;
/* aaaIdentity -> eap_get_identity() */
- Boolean aaaTimeout;
+ bool aaaTimeout;
};
struct eap_server_erp_key {
@@ -108,38 +108,162 @@ struct eapol_callbacks {
};
struct eap_config {
+ /**
+ * ssl_ctx - TLS context
+ *
+ * This is passed to the EAP server implementation as a callback
+ * context for TLS operations.
+ */
void *ssl_ctx;
void *msg_ctx;
+
+ /**
+ * eap_sim_db_priv - EAP-SIM/AKA database context
+ *
+ * This is passed to the EAP-SIM/AKA server implementation as a
+ * callback context.
+ */
void *eap_sim_db_priv;
- Boolean backend_auth;
+ bool backend_auth;
int eap_server;
+
+ /**
+ * pwd_group - The D-H group assigned for EAP-pwd
+ *
+ * If EAP-pwd is not used it can be set to zero.
+ */
u16 pwd_group;
+
+ /**
+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+ *
+ * This parameter is used to set a key for EAP-FAST to encrypt the
+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+ * set, must point to a 16-octet key.
+ */
u8 *pac_opaque_encr_key;
+
+ /**
+ * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+ *
+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+ * is a variable length field, but due to some existing implementations
+ * requiring A-ID to be 16 octets in length, it is recommended to use
+ * that length for the field to provide interoperability with deployed
+ * peer implementations.
+ */
u8 *eap_fast_a_id;
+
+ /**
+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+ */
size_t eap_fast_a_id_len;
+ /**
+ * eap_fast_a_id_info - EAP-FAST authority identifier information
+ *
+ * This A-ID-Info contains a user-friendly name for the A-ID. For
+ * example, this could be the enterprise and server names in
+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+ * is not used, this can be set to %NULL.
+ */
char *eap_fast_a_id_info;
- int eap_fast_prov;
+
+ /**
+ * eap_fast_prov - EAP-FAST provisioning modes
+ *
+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+ * 2 = only authenticated provisioning allowed, 3 = both provisioning
+ * modes allowed.
+ */
+ enum {
+ NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
+ } eap_fast_prov;
+
+ /**
+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+ *
+ * This is the hard limit on how long a provisioned PAC-Key can be
+ * used.
+ */
int pac_key_lifetime;
+
+ /**
+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+ *
+ * This is a soft limit on the PAC-Key. The server will automatically
+ * generate a new PAC-Key when this number of seconds (or fewer) of the
+ * lifetime remains.
+ */
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ enum eap_teap_id {
+ EAP_TEAP_ID_ALLOW_ANY = 0,
+ EAP_TEAP_ID_REQUIRE_USER = 1,
+ EAP_TEAP_ID_REQUIRE_MACHINE = 2,
+ EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
+ EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
+ } eap_teap_id;
+
+ /**
+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+ *
+ * This controls whether the protected success/failure indication
+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+ */
int eap_sim_aka_result_ind;
int eap_sim_id;
+
+ /**
+ * tnc - Trusted Network Connect (TNC)
+ *
+ * This controls whether TNC is enabled and will be required before the
+ * peer is allowed to connect. Note: This is only used with EAP-TTLS
+ * and EAP-FAST. If any other EAP method is enabled, the peer will be
+ * allowed to connect without TNC.
+ */
int tnc;
+
+ /**
+ * wps - Wi-Fi Protected Setup context
+ *
+ * If WPS is used with an external RADIUS server (which is quite
+ * unlikely configuration), this is used to provide a pointer to WPS
+ * context data. Normally, this can be set to %NULL.
+ */
struct wps_context *wps;
- const struct wpabuf *assoc_wps_ie;
- const struct wpabuf *assoc_p2p_ie;
- const u8 *peer_addr;
int fragment_size;
int pbc_in_m1;
- const u8 *server_id;
+ /**
+ * server_id - Server identity
+ */
+ u8 *server_id;
size_t server_id_len;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
int erp;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
+};
+
+struct eap_session_data {
+ const struct wpabuf *assoc_wps_ie;
+ const struct wpabuf *assoc_p2p_ie;
+ const u8 *peer_addr;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -148,7 +272,8 @@ struct eap_config {
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf);
+ const struct eap_config *conf,
+ const struct eap_session_data *sess);
void eap_server_sm_deinit(struct eap_sm *sm);
int eap_server_sm_step(struct eap_sm *sm);
void eap_sm_notify_cached(struct eap_sm *sm);
@@ -165,5 +290,6 @@ void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
const u8 *challenge, const u8 *response);
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
void eap_user_free(struct eap_user *user);
+void eap_server_config_free(struct eap_config *cfg);
#endif /* EAP_H */
diff --git a/contrib/wpa/src/eap_server/eap_i.h b/contrib/wpa/src/eap_server/eap_i.h
index f9ab32d69d75..28bb564e9331 100644
--- a/contrib/wpa/src/eap_server/eap_i.h
+++ b/contrib/wpa/src/eap_server/eap_i.h
@@ -23,7 +23,7 @@
*/
struct eap_method {
int vendor;
- EapType method;
+ enum eap_type method;
const char *name;
void * (*init)(struct eap_sm *sm);
@@ -32,15 +32,14 @@ struct eap_method {
struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id);
int (*getTimeout)(struct eap_sm *sm, void *priv);
- Boolean (*check)(struct eap_sm *sm, void *priv,
- struct wpabuf *respData);
+ bool (*check)(struct eap_sm *sm, void *priv, struct wpabuf *respData);
void (*process)(struct eap_sm *sm, void *priv,
struct wpabuf *respData);
- Boolean (*isDone)(struct eap_sm *sm, void *priv);
+ bool (*isDone)(struct eap_sm *sm, void *priv);
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
* but it is useful in implementing Policy.getDecision() */
- Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+ bool (*isSuccess)(struct eap_sm *sm, void *priv);
/**
* free - Free EAP method data
@@ -128,7 +127,7 @@ struct eap_sm {
/* Full authenticator state machine local variables */
/* Long-term (maintained between packets) */
- EapType currentMethod;
+ enum eap_type currentMethod;
int currentId;
enum {
METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
@@ -138,13 +137,13 @@ struct eap_sm {
int methodTimeout;
/* Short-term (not maintained between packets) */
- Boolean rxResp;
- Boolean rxInitiate;
+ bool rxResp;
+ bool rxInitiate;
int respId;
- EapType respMethod;
+ enum eap_type respMethod;
int respVendor;
u32 respVendorMethod;
- Boolean ignore;
+ bool ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
@@ -153,8 +152,8 @@ struct eap_sm {
/* Miscellaneous variables */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
- Boolean changed;
- void *eapol_ctx, *msg_ctx;
+ bool changed;
+ void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
u8 *identity;
@@ -167,13 +166,12 @@ struct eap_sm {
struct eap_user *user;
int user_eap_method_index;
int init_phase2;
- void *ssl_ctx;
- struct eap_sim_db_data *eap_sim_db_priv;
- Boolean backend_auth;
- Boolean update_user;
- int eap_server;
+ const struct eap_config *cfg;
+ struct eap_config cfg_buf;
+ bool update_user;
- int num_rounds;
+ unsigned int num_rounds;
+ unsigned int num_rounds_short;
enum {
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
} method_pending;
@@ -181,42 +179,15 @@ struct eap_sm {
u8 *auth_challenge;
u8 *peer_challenge;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- enum {
- NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
- } eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int eap_sim_id;
- int tnc;
- u16 pwd_group;
- struct wps_context *wps;
struct wpabuf *assoc_wps_ie;
struct wpabuf *assoc_p2p_ie;
- Boolean start_reauth;
+ bool start_reauth;
u8 peer_addr[ETH_ALEN];
- /* Fragmentation size for EAP method init() handler */
- int fragment_size;
-
- int pbc_in_m1;
-
- const u8 *server_id;
- size_t server_id_len;
-
- Boolean initiate_reauth_start_sent;
- Boolean try_initiate_reauth;
- int erp;
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
+ bool initiate_reauth_start_sent;
+ bool try_initiate_reauth;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/contrib/wpa/src/eap_server/eap_methods.h b/contrib/wpa/src/eap_server/eap_methods.h
index fdbea7a7ea6e..ad60700fa52f 100644
--- a/contrib/wpa/src/eap_server/eap_methods.h
+++ b/contrib/wpa/src/eap_server/eap_methods.h
@@ -12,14 +12,15 @@
#include "eap_common/eap_defs.h"
const struct eap_method * eap_server_get_eap_method(int vendor,
- EapType method);
+ enum eap_type method);
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_server_method_register(struct eap_method *method);
-EapType eap_server_get_type(const char *name, int *vendor);
+enum eap_type eap_server_get_type(const char *name, int *vendor);
void eap_server_unregister_methods(void);
-const char * eap_server_get_name(int vendor, EapType type);
+const char * eap_server_get_name(int vendor, enum eap_type type);
/* EAP server method registration calls for statically linked in methods */
int eap_server_identity_register(void);
diff --git a/contrib/wpa/src/eap_server/eap_server.c b/contrib/wpa/src/eap_server/eap_server.c
index 568eebd7e77e..0b7a5b98cf30 100644
--- a/contrib/wpa/src/eap_server/eap_server.c
+++ b/contrib/wpa/src/eap_server/eap_server.c
@@ -9,7 +9,7 @@
* in RFC 4137. However, to support backend authentication in RADIUS
* authentication server functionality, parts of backend authenticator (also
* from RFC 4137) are mixed in. This functionality is enabled by setting
- * backend_auth configuration variable to TRUE.
+ * backend_auth configuration variable to true.
*/
#include "includes.h"
@@ -23,8 +23,6 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -37,9 +35,10 @@ static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
static int eap_sm_nextId(struct eap_sm *sm, int id);
static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm,
+ int *vendor);
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method);
static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
@@ -94,7 +93,7 @@ static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
}
msg = eap_msg_alloc(EAP_VENDOR_IETF,
- (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
@@ -215,6 +214,7 @@ SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
}
@@ -222,7 +222,7 @@ SM_STATE(EAP, INITIALIZE)
{
SM_ENTRY(EAP, INITIALIZE);
- if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+ if (sm->eap_if.eapRestart && !sm->cfg->eap_server && sm->identity) {
/*
* Need to allow internal Identity method to be used instead
* of passthrough at the beginning of reauthentication.
@@ -230,19 +230,19 @@ SM_STATE(EAP, INITIALIZE)
eap_server_clear_identity(sm);
}
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
sm->currentId = -1;
- sm->eap_if.eapSuccess = FALSE;
- sm->eap_if.eapFail = FALSE;
- sm->eap_if.eapTimeout = FALSE;
+ sm->eap_if.eapSuccess = false;
+ sm->eap_if.eapFail = false;
+ sm->eap_if.eapTimeout = false;
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
os_free(sm->eap_if.eapSessionId);
sm->eap_if.eapSessionId = NULL;
sm->eap_if.eapSessionIdLen = 0;
- sm->eap_if.eapKeyAvailable = FALSE;
- sm->eap_if.eapRestart = FALSE;
+ sm->eap_if.eapKeyAvailable = false;
+ sm->eap_if.eapRestart = false;
/*
* This is not defined in RFC 4137, but method state needs to be
@@ -256,7 +256,7 @@ SM_STATE(EAP, INITIALIZE)
sm->m = NULL;
sm->user_eap_method_index = 0;
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
sm->currentMethod = EAP_TYPE_NONE;
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
@@ -265,9 +265,10 @@ SM_STATE(EAP, INITIALIZE)
}
}
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->method_pending = METHOD_PENDING_NONE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -299,7 +300,7 @@ SM_STATE(EAP, PICK_UP_METHOD)
}
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"method=%u", sm->currentMethod);
}
@@ -321,10 +322,10 @@ SM_STATE(EAP, RETRANSMIT)
sm->retransCount++;
if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapReq = true;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -336,14 +337,18 @@ SM_STATE(EAP, RECEIVED)
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
sm->num_rounds++;
+ if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
SM_STATE(EAP, DISCARD)
{
SM_ENTRY(EAP, DISCARD);
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapNoReq = true;
}
@@ -353,19 +358,21 @@ SM_STATE(EAP, SEND_REQUEST)
sm->retransCount = 0;
if (sm->eap_if.eapReqData) {
+ if (wpabuf_len(sm->eap_if.eapReqData) >= 20)
+ sm->num_rounds_short = 0;
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = true;
} else {
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
}
} else {
wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
+ sm->eap_if.eapNoReq = true;
}
}
@@ -375,7 +382,7 @@ SM_STATE(EAP, INTEGRITY_CHECK)
SM_ENTRY(EAP, INTEGRITY_CHECK);
if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
- sm->ignore = TRUE;
+ sm->ignore = true;
return;
}
@@ -529,7 +536,7 @@ SM_STATE(EAP, METHOD_RESPONSE)
sm->eap_if.eapSessionId,
sm->eap_if.eapSessionIdLen);
}
- if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ if (sm->cfg->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
@@ -541,11 +548,11 @@ SM_STATE(EAP, METHOD_RESPONSE)
SM_STATE(EAP, PROPOSE_METHOD)
{
int vendor;
- EapType type;
+ enum eap_type type;
SM_ENTRY(EAP, PROPOSE_METHOD);
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
@@ -579,7 +586,7 @@ try_another_method:
else
sm->methodState = METHOD_PROPOSED;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
vendor, sm->currentMethod);
@@ -633,10 +640,10 @@ SM_STATE(EAP, TIMEOUT_FAILURE)
{
SM_ENTRY(EAP, TIMEOUT_FAILURE);
- sm->eap_if.eapTimeout = TRUE;
+ sm->eap_if.eapTimeout = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR, MAC2STR(sm->peer_addr));
}
@@ -648,9 +655,9 @@ SM_STATE(EAP, FAILURE)
sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
- sm->eap_if.eapFail = TRUE;
+ sm->eap_if.eapFail = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -664,10 +671,10 @@ SM_STATE(EAP, SUCCESS)
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
if (sm->eap_if.eapKeyData)
- sm->eap_if.eapKeyAvailable = TRUE;
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapKeyAvailable = true;
+ sm->eap_if.eapSuccess = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -676,8 +683,8 @@ SM_STATE(EAP, INITIATE_REAUTH_START)
{
SM_ENTRY(EAP, INITIATE_REAUTH_START);
- sm->initiate_reauth_start_sent = TRUE;
- sm->try_initiate_reauth = TRUE;
+ sm->initiate_reauth_start_sent = true;
+ sm->try_initiate_reauth = true;
sm->currentId = eap_sm_nextId(sm, sm->currentId);
wpa_printf(MSG_DEBUG,
"EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
@@ -720,7 +727,8 @@ static void erp_send_finish_reauth(struct eap_sm *sm,
plen = 1 + 2 + 2 + os_strlen(nai);
if (hash_len)
plen += 1 + hash_len;
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
plen, EAP_CODE_FINISH, id);
if (msg == NULL)
return;
@@ -752,8 +760,8 @@ static void erp_send_finish_reauth(struct eap_sm *sm,
sm->lastReqData = NULL;
if ((flags & 0x80) || !erp) {
- sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ sm->eap_if.eapFail = true;
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
return;
}
@@ -776,12 +784,12 @@ static void erp_send_finish_reauth(struct eap_sm *sm,
return;
}
sm->eap_if.eapKeyDataLen = erp->rRK_len;
- sm->eap_if.eapKeyAvailable = TRUE;
+ sm->eap_if.eapKeyAvailable = true;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapSuccess = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -803,9 +811,10 @@ SM_STATE(EAP, INITIATE_RECEIVED)
SM_ENTRY(EAP, INITIATE_RECEIVED);
- sm->rxInitiate = FALSE;
+ sm->rxInitiate = false;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ pos = eap_hdr_validate(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
sm->eap_if.eapRespData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
@@ -852,7 +861,7 @@ SM_STATE(EAP, INITIATE_RECEIVED)
os_memcpy(nai, parse.keyname, parse.keyname_len);
nai[parse.keyname_len] = '\0';
- if (!sm->eap_server) {
+ if (!sm->cfg->eap_server) {
/*
* In passthrough case, EAP-Initiate/Re-auth replaces
* EAP Identity exchange. Use keyName-NAI as the user identity
@@ -979,7 +988,7 @@ report_error:
return;
fail:
- sm->ignore = TRUE;
+ sm->ignore = true;
}
#endif /* CONFIG_ERP */
@@ -991,7 +1000,7 @@ SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
wpabuf_free(sm->eap_if.aaaEapRespData);
sm->eap_if.aaaEapRespData = NULL;
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
}
@@ -1012,10 +1021,10 @@ SM_STATE(EAP, RETRANSMIT2)
sm->retransCount++;
if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapReq = true;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1032,8 +1041,8 @@ SM_STATE(EAP, RECEIVED2)
SM_STATE(EAP, DISCARD2)
{
SM_ENTRY(EAP, DISCARD2);
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapNoReq = true;
}
@@ -1045,17 +1054,17 @@ SM_STATE(EAP, SEND_REQUEST2)
if (sm->eap_if.eapReqData) {
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = true;
} else {
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
}
} else {
wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
+ sm->eap_if.eapNoReq = true;
}
}
@@ -1094,11 +1103,11 @@ SM_STATE(EAP, AAA_IDLE)
{
SM_ENTRY(EAP, AAA_IDLE);
- sm->eap_if.aaaFail = FALSE;
- sm->eap_if.aaaSuccess = FALSE;
- sm->eap_if.aaaEapReq = FALSE;
- sm->eap_if.aaaEapNoReq = FALSE;
- sm->eap_if.aaaEapResp = TRUE;
+ sm->eap_if.aaaFail = false;
+ sm->eap_if.aaaSuccess = false;
+ sm->eap_if.aaaEapReq = false;
+ sm->eap_if.aaaEapNoReq = false;
+ sm->eap_if.aaaEapResp = true;
}
@@ -1106,10 +1115,10 @@ SM_STATE(EAP, TIMEOUT_FAILURE2)
{
SM_ENTRY(EAP, TIMEOUT_FAILURE2);
- sm->eap_if.eapTimeout = TRUE;
+ sm->eap_if.eapTimeout = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR, MAC2STR(sm->peer_addr));
}
@@ -1118,9 +1127,9 @@ SM_STATE(EAP, FAILURE2)
SM_ENTRY(EAP, FAILURE2);
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
- sm->eap_if.eapFail = TRUE;
+ sm->eap_if.eapFail = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1140,16 +1149,16 @@ SM_STATE(EAP, SUCCESS2)
sm->eap_if.eapKeyDataLen = 0;
}
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapSuccess = true;
/*
* Start reauthentication with identity request even though we know the
* previously used identity. This is needed to get reauthentication
* started properly.
*/
- sm->start_reauth = TRUE;
+ sm->start_reauth = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1160,17 +1169,26 @@ SM_STEP(EAP)
SM_ENTER_GLOBAL(EAP, INITIALIZE);
else if (!sm->eap_if.portEnabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
- else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
- if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+ else if (sm->num_rounds > sm->cfg->max_auth_rounds) {
+ if (sm->num_rounds == sm->cfg->max_auth_rounds + 1) {
wpa_printf(MSG_DEBUG, "EAP: more than %d "
"authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ sm->cfg->max_auth_rounds);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > sm->cfg->max_auth_rounds_short) {
+ if (sm->num_rounds_short ==
+ sm->cfg->max_auth_rounds_short + 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: more than %d authentication rounds (short) - abort",
+ sm->cfg->max_auth_rounds_short);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else switch (sm->EAP_state) {
case EAP_INITIALIZE:
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
if (!sm->rxResp)
SM_ENTER(EAP, SELECT_ACTION);
else if (sm->rxResp &&
@@ -1199,7 +1217,7 @@ SM_STEP(EAP)
case EAP_IDLE:
if (sm->eap_if.retransWhile == 0) {
if (sm->try_initiate_reauth) {
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
SM_ENTER(EAP, SELECT_ACTION);
} else {
SM_ENTER(EAP, RETRANSMIT);
@@ -1333,7 +1351,7 @@ SM_STEP(EAP)
else if (sm->decision == DECISION_INITIATE_REAUTH_START)
SM_ENTER(EAP, INITIATE_REAUTH_START);
#ifdef CONFIG_ERP
- else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ else if (sm->cfg->eap_server && sm->cfg->erp && sm->rxInitiate)
SM_ENTER(EAP, INITIATE_RECEIVED);
#endif /* CONFIG_ERP */
else
@@ -1343,7 +1361,7 @@ SM_STEP(EAP)
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_INITIATE_RECEIVED:
- if (!sm->eap_server)
+ if (!sm->cfg->eap_server)
SM_ENTER(EAP, SELECT_ACTION);
break;
case EAP_TIMEOUT_FAILURE:
@@ -1473,8 +1491,8 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
size_t plen;
/* parse rxResp, respId, respMethod */
- sm->rxResp = FALSE;
- sm->rxInitiate = FALSE;
+ sm->rxResp = false;
+ sm->rxInitiate = false;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
sm->respVendor = EAP_VENDOR_IETF;
@@ -1500,9 +1518,9 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
sm->respId = hdr->identifier;
if (hdr->code == EAP_CODE_RESPONSE)
- sm->rxResp = TRUE;
+ sm->rxResp = true;
else if (hdr->code == EAP_CODE_INITIATE)
- sm->rxInitiate = TRUE;
+ sm->rxInitiate = true;
if (plen > sizeof(*hdr)) {
u8 *pos = (u8 *) (hdr + 1);
@@ -1669,9 +1687,9 @@ static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
}
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
{
- EapType next;
+ enum eap_type next;
int idx = sm->user_eap_method_index;
/* In theory, there should be no problems with starting
@@ -1684,7 +1702,7 @@ static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
if (sm->identity == NULL || sm->currentId == -1) {
*vendor = EAP_VENDOR_IETF;
next = EAP_TYPE_IDENTITY;
- sm->update_user = TRUE;
+ sm->update_user = true;
} else if (sm->user && idx < EAP_MAX_METHODS &&
(sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
sm->user->methods[idx].method != EAP_TYPE_NONE)) {
@@ -1703,7 +1721,7 @@ static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
{
- if (!sm->eap_server && sm->identity && !sm->start_reauth) {
+ if (!sm->cfg->eap_server && sm->identity && !sm->start_reauth) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
return DECISION_PASSTHROUGH;
}
@@ -1712,7 +1730,7 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
sm->m->isSuccess(sm, sm->eap_method_priv)) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
"SUCCESS");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_SUCCESS;
}
@@ -1720,7 +1738,7 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
!sm->m->isSuccess(sm, sm->eap_method_priv)) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
"FAILURE");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_FAILURE;
}
@@ -1747,12 +1765,12 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
"identity request loop -> FAILURE");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_FAILURE;
}
- sm->update_user = FALSE;
+ sm->update_user = false;
}
- sm->start_reauth = FALSE;
+ sm->start_reauth = false;
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
(sm->user->methods[sm->user_eap_method_index].vendor !=
@@ -1783,9 +1801,9 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
}
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method)
{
- return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
+ return method == EAP_TYPE_IDENTITY;
}
@@ -1802,7 +1820,7 @@ int eap_server_sm_step(struct eap_sm *sm)
{
int res = 0;
do {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(EAP);
if (sm->changed)
res = 1;
@@ -1834,7 +1852,8 @@ void eap_user_free(struct eap_user *user)
*/
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *conf)
+ const struct eap_config *conf,
+ const struct eap_session_data *sess)
{
struct eap_sm *sm;
@@ -1844,54 +1863,15 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
- sm->ssl_ctx = conf->ssl_ctx;
- sm->msg_ctx = conf->msg_ctx;
- sm->eap_sim_db_priv = conf->eap_sim_db_priv;
- sm->backend_auth = conf->backend_auth;
- sm->eap_server = conf->eap_server;
- if (conf->pac_opaque_encr_key) {
- sm->pac_opaque_encr_key = os_malloc(16);
- if (sm->pac_opaque_encr_key) {
- os_memcpy(sm->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (sm->eap_fast_a_id) {
- os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- sm->eap_fast_prov = conf->eap_fast_prov;
- sm->pac_key_lifetime = conf->pac_key_lifetime;
- sm->pac_key_refresh_time = conf->pac_key_refresh_time;
- sm->eap_teap_auth = conf->eap_teap_auth;
- sm->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
- sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- sm->eap_sim_id = conf->eap_sim_id;
- sm->tnc = conf->tnc;
- sm->wps = conf->wps;
- if (conf->assoc_wps_ie)
- sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
- if (conf->assoc_p2p_ie)
- sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
- if (conf->peer_addr)
- os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
- sm->fragment_size = conf->fragment_size;
- sm->pwd_group = conf->pwd_group;
- sm->pbc_in_m1 = conf->pbc_in_m1;
- sm->server_id = conf->server_id;
- sm->server_id_len = conf->server_id_len;
- sm->erp = conf->erp;
- sm->tls_session_lifetime = conf->tls_session_lifetime;
- sm->tls_flags = conf->tls_flags;
-
+ sm->cfg = conf;
+ if (sess->assoc_wps_ie)
+ sm->assoc_wps_ie = wpabuf_dup(sess->assoc_wps_ie);
+ if (sess->assoc_p2p_ie)
+ sm->assoc_p2p_ie = wpabuf_dup(sess->assoc_p2p_ie);
+ if (sess->peer_addr)
+ os_memcpy(sm->peer_addr, sess->peer_addr, ETH_ALEN);
#ifdef CONFIG_TESTING_OPTIONS
- sm->tls_test_flags = conf->tls_test_flags;
+ sm->tls_test_flags = sess->tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -1921,9 +1901,6 @@ void eap_server_sm_deinit(struct eap_sm *sm)
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
os_free(sm->serial_num);
- os_free(sm->pac_opaque_encr_key);
- os_free(sm->eap_fast_a_id);
- os_free(sm->eap_fast_a_id_info);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
@@ -2113,3 +2090,15 @@ void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
source, user, hex_challenge, hex_response);
}
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void eap_server_config_free(struct eap_config *cfg)
+{
+ if (!cfg)
+ return;
+ os_free(cfg->pac_opaque_encr_key);
+ os_free(cfg->eap_fast_a_id);
+ os_free(cfg->eap_fast_a_id_info);
+ os_free(cfg->server_id);
+ os_free(cfg);
+}
diff --git a/contrib/wpa/src/eap_server/eap_server_aka.c b/contrib/wpa/src/eap_server/eap_server_aka.c
index 4dadfe197c6b..e9bf0300c16f 100644
--- a/contrib/wpa/src/eap_server/eap_server_aka.c
+++ b/contrib/wpa/src/eap_server/eap_server_aka.c
@@ -100,7 +100,7 @@ static int eap_aka_check_identity_reauth(struct eap_sm *sm,
return 0;
wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
- data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ data->reauth = eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
@@ -157,7 +157,7 @@ static void eap_aka_check_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
if (permanent == NULL) {
os_free(username);
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -182,7 +182,7 @@ static void * eap_aka_init(struct eap_sm *sm)
{
struct eap_aka_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -208,7 +208,7 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
/* TODO: make ANID configurable; see 3GPP TS 24.302 */
char *network_name = "WLAN";
- if (sm->eap_sim_db_priv == NULL) {
+ if (sm->cfg->eap_sim_db_priv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -393,13 +393,13 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (!(sm->eap_sim_id & 0x01)) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
/* Use of pseudonyms disabled in configuration */
data->next_pseudonym = NULL;
} else if (!nonce_s) {
data->next_pseudonym =
eap_sim_db_get_next_pseudonym(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -407,13 +407,13 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (!(sm->eap_sim_id & 0x02)) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
/* Use of fast reauth disabled in configuration */
data->next_reauth_id = NULL;
} else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
data->next_reauth_id =
eap_sim_db_get_next_reauth_id(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -505,7 +505,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -582,7 +582,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -664,8 +664,8 @@ static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_aka_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_aka_data *data = priv;
const u8 *pos;
@@ -675,25 +675,25 @@ static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
&len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
+static bool eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
{
if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
- return FALSE;
+ return false;
switch (data->state) {
case IDENTITY:
if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case CHALLENGE:
@@ -701,30 +701,30 @@ static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case REAUTH:
if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case NOTIFICATION:
if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
default:
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
"processing a response", data->state);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -767,7 +767,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -803,7 +803,7 @@ static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
size_t identity_len;
int res;
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ res = eap_sim_db_get_aka_auth(sm->cfg->eap_sim_db_priv, data->permanent,
data->rand, data->autn, data->ik,
data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
@@ -998,7 +998,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1006,14 +1006,15 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
eap_aka_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1021,7 +1022,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1051,7 +1052,7 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_resynchronize(sm->cfg->eap_sim_db_priv, data->permanent,
attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
@@ -1118,7 +1119,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1128,7 +1129,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1136,7 +1137,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1144,7 +1145,8 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
}
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -1153,7 +1155,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
@@ -1267,7 +1269,7 @@ static void eap_aka_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
+static bool eap_aka_isDone(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1306,7 +1308,7 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_aka_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_eke.c b/contrib/wpa/src/eap_server/eap_server_eke.c
index 71580bf7bf52..eac3245cd1f2 100644
--- a/contrib/wpa/src/eap_server/eap_server_eke.c
+++ b/contrib/wpa/src/eap_server/eap_server_eke.c
@@ -84,11 +84,11 @@ static void * eap_eke_init(struct eap_sm *sm)
eap_eke_state(data, IDENTITY);
data->serverid_type = EAP_EKE_ID_OPAQUE;
- for (i = 0; i < sm->server_id_len; i++) {
- if (sm->server_id[i] == '.' &&
+ for (i = 0; i < sm->cfg->server_id_len; i++) {
+ if (sm->cfg->server_id[i] == '.' &&
data->serverid_type == EAP_EKE_ID_OPAQUE)
data->serverid_type = EAP_EKE_ID_FQDN;
- if (sm->server_id[i] == '@')
+ if (sm->cfg->server_id[i] == '@')
data->serverid_type = EAP_EKE_ID_NAI;
}
@@ -186,7 +186,7 @@ static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
- plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+ plen = 2 + 4 * 4 + 1 + sm->cfg->server_id_len;
msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
if (msg == NULL)
return NULL;
@@ -223,7 +223,7 @@ static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
/* Server IDType + Identity */
wpabuf_put_u8(msg, data->serverid_type);
- wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(msg, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_free(data->msgs);
data->msgs = wpabuf_dup(msg);
@@ -252,7 +252,7 @@ static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
if (eap_eke_derive_key(&data->sess, sm->user->password,
sm->user->password_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, data->key) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -338,7 +338,7 @@ static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
wpabuf_put(msg, prot_len);
if (eap_eke_derive_ka(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_p, data->nonce_s) < 0) {
wpabuf_free(msg);
@@ -380,8 +380,8 @@ static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_eke_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_eke_data *data = priv;
size_t len;
@@ -391,28 +391,28 @@ static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
- return TRUE;
+ return true;
}
eke_exch = *pos;
wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
- return FALSE;
+ return false;
if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
- return FALSE;
+ return false;
if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
- return FALSE;
+ return false;
if (eke_exch == EAP_EKE_FAILURE)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
eke_exch, data->state);
- return TRUE;
+ return true;
}
@@ -552,7 +552,7 @@ static void eap_eke_process_commit(struct eap_sm *sm,
}
if (eap_eke_derive_ke_ki(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -641,7 +641,8 @@ static void eap_eke_process_confirm(struct eap_sm *sm,
return;
}
- if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+ if (eap_eke_derive_msk(&data->sess, sm->cfg->server_id,
+ sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_s, data->nonce_p,
data->msk, data->emsk) < 0) {
@@ -715,7 +716,7 @@ static void eap_eke_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+static bool eap_eke_isDone(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -756,7 +757,7 @@ static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_eke_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_fast.c b/contrib/wpa/src/eap_server/eap_server_fast.c
index a63f820465c8..55d48d91f606 100644
--- a/contrib/wpa/src/eap_server/eap_server_fast.c
+++ b/contrib/wpa/src/eap_server/eap_server_fast.c
@@ -108,8 +108,8 @@ static void eap_fast_state(struct eap_fast_data *data, int state)
}
-static EapType eap_fast_req_failure(struct eap_sm *sm,
- struct eap_fast_data *data)
+static enum eap_type eap_fast_req_failure(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
/* TODO: send Result TLV(FAILURE) */
eap_fast_state(data, FAILURE);
@@ -278,7 +278,7 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ sks = eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +304,7 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
{
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
- eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -440,7 +440,7 @@ static void * eap_fast_init(struct eap_sm *sm)
return NULL;
}
- if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_cipher_list(sm->cfg->ssl_ctx, data->ssl.conn,
ciphers) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
"suites");
@@ -448,7 +448,8 @@ static void * eap_fast_init(struct eap_sm *sm)
return NULL;
}
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_fast_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
@@ -457,47 +458,48 @@ static void * eap_fast_init(struct eap_sm *sm)
return NULL;
}
- if (sm->pac_opaque_encr_key == NULL) {
+ if (sm->cfg->pac_opaque_encr_key == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
"configured");
eap_fast_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (sm->eap_fast_a_id == NULL) {
+ if (sm->cfg->eap_fast_a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id = os_memdup(sm->eap_fast_a_id, sm->eap_fast_a_id_len);
+ data->srv_id = os_memdup(sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
if (data->srv_id == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_len = sm->eap_fast_a_id_len;
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (sm->eap_fast_a_id_info == NULL) {
+ if (sm->cfg->eap_fast_a_id_info == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (data->srv_id_info == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -552,8 +554,8 @@ static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
"information");
eap_fast_state(data, FAILURE);
@@ -872,7 +874,8 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
case START:
return eap_fast_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_fast_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -926,8 +929,8 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_fast_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -935,23 +938,22 @@ static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -973,7 +975,8 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
struct eap_fast_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -999,8 +1002,9 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
"TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -1008,14 +1012,17 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1035,8 +1042,9 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1047,6 +1055,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
"Identity not found in the user "
"database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
break;
}
@@ -1057,23 +1066,28 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
* Only EAP-MSCHAPv2 is allowed for anonymous
* provisioning.
*/
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_MSCHAPV2;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_fast_update_icmk(sm, data);
eap_fast_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1087,7 +1101,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
break;
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1335,8 +1349,8 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
"use unauthenticated provisioning which is "
"disabled");
@@ -1344,8 +1358,8 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
eap_fast_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1397,7 +1411,7 @@ static void eap_fast_process_phase2(struct eap_sm *sm,
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
@@ -1457,7 +1471,7 @@ static int eap_fast_process_phase1(struct eap_sm *sm,
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1474,7 +1488,8 @@ static int eap_fast_process_phase1(struct eap_sm *sm,
static int eap_fast_process_phase2_start(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
os_free(sm->identity);
@@ -1488,10 +1503,12 @@ static int eap_fast_process_phase2_start(struct eap_sm *sm,
"Phase2 Identity not found "
"in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
"known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
@@ -1499,10 +1516,11 @@ static int eap_fast_process_phase2_start(struct eap_sm *sm,
eap_fast_state(data, PHASE2_METHOD);
} else {
eap_fast_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_fast_phase2_init(sm, data, next_type);
+ return eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1545,7 +1563,7 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
+static bool eap_fast_isDone(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1596,7 +1614,7 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_fast_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_gpsk.c b/contrib/wpa/src/eap_server/eap_server_gpsk.c
index bebb17f40aaa..4081b9f99c19 100644
--- a/contrib/wpa/src/eap_server/eap_server_gpsk.c
+++ b/contrib/wpa/src/eap_server/eap_server_gpsk.c
@@ -117,7 +117,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
data->rand_server, EAP_GPSK_RAND_LEN);
- len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
+ len = 1 + 2 + sm->cfg->server_id_len + EAP_GPSK_RAND_LEN + 2 +
data->csuite_count * sizeof(struct eap_gpsk_csuite);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -129,8 +129,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
}
wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
wpabuf_put_be16(req,
data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -152,7 +152,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
- len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->cfg->server_id_len +
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -168,8 +168,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
csuite = wpabuf_put(req, sizeof(*csuite));
WPA_PUT_BE32(csuite->vendor, data->vendor);
WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -208,8 +208,8 @@ static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_gpsk_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_gpsk_data *data = priv;
const u8 *pos;
@@ -218,21 +218,21 @@ static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
- return FALSE;
+ return false;
if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
*pos, data->state);
- return TRUE;
+ return true;
}
@@ -294,8 +294,8 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (alen != sm->server_id_len ||
- os_memcmp(pos, sm->server_id, alen) != 0) {
+ if (alen != sm->cfg->server_id_len ||
+ os_memcmp(pos, sm->cfg->server_id, alen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
"GPSK-2 did not match");
eap_gpsk_state(data, FAILURE);
@@ -409,7 +409,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->msk, data->emsk,
data->sk, &data->sk_len,
data->pk, &data->pk_len) < 0) {
@@ -423,7 +423,8 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id,
+ sm->cfg->server_id_len,
EAP_TYPE_GPSK,
data->session_id, &data->id_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
@@ -559,7 +560,7 @@ static void eap_gpsk_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isDone(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -600,7 +601,7 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_gtc.c b/contrib/wpa/src/eap_server/eap_server_gtc.c
index fcccbcbd5efa..6310793a7d6a 100644
--- a/contrib/wpa/src/eap_server/eap_server_gtc.c
+++ b/contrib/wpa/src/eap_server/eap_server_gtc.c
@@ -74,8 +74,8 @@ static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_gtc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -83,10 +83,10 @@ static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -184,14 +184,14 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_gtc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_gtc_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_gtc_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_identity.c b/contrib/wpa/src/eap_server/eap_server_identity.c
index 1b1db53f25b2..813e1d6de51d 100644
--- a/contrib/wpa/src/eap_server/eap_server_identity.c
+++ b/contrib/wpa/src/eap_server/eap_server_identity.c
@@ -79,8 +79,8 @@ static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv,
}
-static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_identity_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -89,10 +89,10 @@ static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
respData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -127,7 +127,7 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
os_free(buf);
}
if (sm->identity)
- sm->update_user = TRUE;
+ sm->update_user = true;
os_free(sm->identity);
sm->identity = os_malloc(len ? len : 1);
if (sm->identity == NULL) {
@@ -140,14 +140,14 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
+static bool eap_identity_isDone(struct eap_sm *sm, void *priv)
{
struct eap_identity_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_identity_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_identity_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_ikev2.c b/contrib/wpa/src/eap_server/eap_server_ikev2.c
index 32e6872045c5..ef3cc8cccebf 100644
--- a/contrib/wpa/src/eap_server/eap_server_ikev2.c
+++ b/contrib/wpa/src/eap_server/eap_server_ikev2.c
@@ -87,8 +87,8 @@ static void * eap_ikev2_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
data->state = MSG;
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- IKEV2_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : IKEV2_FRAGMENT_SIZE;
data->ikev2.state = SA_INIT;
data->ikev2.peer_auth = PEER_AUTH_SECRET;
data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
@@ -103,10 +103,10 @@ static void * eap_ikev2_init(struct eap_sm *sm)
data->ikev2.proposal.encr = ENCR_AES_CBC;
data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
- data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len);
+ data->ikev2.IDi = os_memdup(sm->cfg->server_id, sm->cfg->server_id_len);
if (data->ikev2.IDi == NULL)
goto failed;
- data->ikev2.IDi_len = sm->server_id_len;
+ data->ikev2.IDi_len = sm->cfg->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
data->ikev2.cb_ctx = sm;
@@ -236,8 +236,8 @@ static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_ikev2_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -246,10 +246,10 @@ static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
&len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -414,7 +414,7 @@ static void eap_ikev2_process(struct eap_sm *sm, void *priv,
eap_ikev2_state(data, FAIL);
return;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
if (eap_ikev2_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
@@ -465,14 +465,14 @@ static void eap_ikev2_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isDone(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE || data->state == FAIL;
}
-static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
diff --git a/contrib/wpa/src/eap_server/eap_server_md5.c b/contrib/wpa/src/eap_server/eap_server_md5.c
index cf5ceb1d1529..c9b500cdb1a5 100644
--- a/contrib/wpa/src/eap_server/eap_server_md5.c
+++ b/contrib/wpa/src/eap_server/eap_server_md5.c
@@ -73,8 +73,8 @@ static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_md5_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -82,16 +82,16 @@ static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
- return TRUE;
+ return true;
}
if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
"(response_len=%d payload_len=%lu",
*pos, (unsigned long) len);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -136,14 +136,14 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv)
+static bool eap_md5_isDone(struct eap_sm *sm, void *priv)
{
struct eap_md5_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_md5_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_md5_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_methods.c b/contrib/wpa/src/eap_server/eap_server_methods.c
index 79ed3447ac0a..f37c9c383594 100644
--- a/contrib/wpa/src/eap_server/eap_server_methods.c
+++ b/contrib/wpa/src/eap_server/eap_server_methods.c
@@ -22,7 +22,8 @@ static struct eap_method *eap_methods;
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_server_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -42,7 +43,7 @@ const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_server_get_type(const char *name, int *vendor)
+enum eap_type eap_server_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -69,7 +70,8 @@ EapType eap_server_get_type(const char *name, int *vendor)
* is not needed anymore.
*/
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
@@ -163,7 +165,7 @@ void eap_server_unregister_methods(void)
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_server_get_name(int vendor, EapType type)
+const char * eap_server_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
diff --git a/contrib/wpa/src/eap_server/eap_server_mschapv2.c b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
index e9e03b0afb45..9b3eb26ef453 100644
--- a/contrib/wpa/src/eap_server/eap_server_mschapv2.c
+++ b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
@@ -109,7 +109,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
return NULL;
}
- ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->cfg->server_id_len;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
@@ -131,7 +131,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
wpabuf_put(req, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
data->auth_challenge, CHALLENGE_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -235,8 +235,8 @@ static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
}
-static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_mschapv2_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_mschapv2_data *data = priv;
struct eap_mschapv2_hdr *resp;
@@ -247,7 +247,7 @@ static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
&len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
- return TRUE;
+ return true;
}
resp = (struct eap_mschapv2_hdr *) pos;
@@ -255,7 +255,7 @@ static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
resp->op_code != MSCHAPV2_OP_RESPONSE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == SUCCESS_REQ &&
@@ -263,17 +263,17 @@ static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
resp->op_code != MSCHAPV2_OP_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
"Failure - ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == FAILURE_REQ &&
resp->op_code != MSCHAPV2_OP_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
"- ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -531,7 +531,7 @@ static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -564,7 +564,7 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_pax.c b/contrib/wpa/src/eap_server/eap_server_pax.c
index 5ed29efd1d3c..fb089d50a141 100644
--- a/contrib/wpa/src/eap_server/eap_server_pax.c
+++ b/contrib/wpa/src/eap_server/eap_server_pax.c
@@ -195,8 +195,8 @@ static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_pax_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_pax_data *data = priv;
struct eap_pax_hdr *resp;
@@ -207,7 +207,7 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
- return TRUE;
+ return true;
}
mlen = sizeof(struct eap_hdr) + 1 + len;
@@ -225,14 +225,14 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
resp->op_code != EAP_PAX_OP_STD_2) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == PAX_STD_3 &&
resp->op_code != EAP_PAX_OP_ACK) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (resp->op_code != EAP_PAX_OP_STD_2 &&
@@ -244,38 +244,38 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
if (data->mac_id != resp->mac_id) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
"received 0x%x", data->mac_id, resp->mac_id);
- return TRUE;
+ return true;
}
if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
"received 0x%x", EAP_PAX_DH_GROUP_NONE,
resp->dh_group_id);
- return TRUE;
+ return true;
}
if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
"received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
resp->public_key_id);
- return TRUE;
+ return true;
}
if (resp->flags & EAP_PAX_FLAGS_MF) {
/* TODO: add support for reassembling fragments */
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
- return TRUE;
+ return true;
}
if (resp->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
- return TRUE;
+ return true;
}
if (data->keys_set) {
if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
- return TRUE;
+ return true;
}
icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
@@ -285,18 +285,18 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
NULL, 0, NULL, 0, icvbuf) < 0) {
wpa_printf(MSG_INFO,
"EAP-PAX: Failed to calculate ICV");
- return TRUE;
+ return true;
}
if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
@@ -513,7 +513,7 @@ static void eap_pax_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
+static bool eap_pax_isDone(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -563,7 +563,7 @@ static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_pax_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_peap.c b/contrib/wpa/src/eap_server/eap_server_peap.c
index 5e125acf7f93..f526e8bf7377 100644
--- a/contrib/wpa/src/eap_server/eap_server_peap.c
+++ b/contrib/wpa/src/eap_server/eap_server_peap.c
@@ -105,8 +105,8 @@ static void eap_peap_valid_session(struct eap_sm *sm,
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime ||
- tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!sm->cfg->tls_session_lifetime ||
+ tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -325,18 +325,32 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
u8 *tk;
u8 isk[32], imck[60];
int res;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
* phase 1 of PEAP (based on TLS).
*/
- tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
- NULL, 0, EAP_TLS_KEY_LEN);
+ tk = eap_server_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
+ EAP_TLS_KEY_LEN);
if (tk == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
- if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
/* Fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, tk, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -498,7 +512,25 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
os_free(hdr);
- return encr_req;
+ if (!data->ssl.tls_v13 ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
+ wpabuf_free(data->ssl.tls_out);
+ data->ssl.tls_out_pos = 0;
+ return encr_req;
+ }
+
+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr_req)) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Failed to resize output buffer");
+ wpabuf_free(encr_req);
+ return NULL;
+ }
+ wpabuf_put_buf(data->ssl.tls_out, encr_req);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-PEAP: Data appended to the message", encr_req);
+ os_free(encr_req);
+
+ return data->ssl.tls_out;
}
@@ -521,7 +553,8 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
@@ -546,8 +579,6 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
break;
case SUCCESS_REQ:
- wpabuf_free(data->ssl.tls_out);
- data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
1);
break;
@@ -568,8 +599,8 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_peap_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -577,15 +608,15 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- int vendor, EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
@@ -1020,7 +1051,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
}
#ifdef EAP_SERVER_TNC
- if (data->state != PHASE2_SOH && sm->tnc &&
+ if (data->state != PHASE2_SOH && sm->cfg->tnc &&
data->peap_version == 0) {
eap_peap_state(data, PHASE2_SOH);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
@@ -1077,7 +1108,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
@@ -1237,8 +1268,8 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
}
if (data->state == SUCCESS ||
- !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ !tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -1288,7 +1319,7 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
+static bool eap_peap_isDone(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1299,6 +1330,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1331,9 +1366,17 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
return eapKeyData;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
@@ -1352,6 +1395,10 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1361,9 +1408,17 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
@@ -1382,7 +1437,7 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_peap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_psk.c b/contrib/wpa/src/eap_server/eap_server_psk.c
index 0eab89339ff6..f55f70dd8493 100644
--- a/contrib/wpa/src/eap_server/eap_server_psk.c
+++ b/contrib/wpa/src/eap_server/eap_server_psk.c
@@ -68,7 +68,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
data->rand_s, EAP_PSK_RAND_LEN);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
- sizeof(*psk) + sm->server_id_len,
+ sizeof(*psk) + sm->cfg->server_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -80,7 +80,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
psk = wpabuf_put(req, sizeof(*psk));
psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -110,13 +110,13 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
- buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
+ buflen = sm->cfg->server_id_len + EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL)
goto fail;
- os_memcpy(buf, sm->server_id, sm->server_id_len);
- os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, sm->cfg->server_id, sm->cfg->server_id_len);
+ os_memcpy(buf + sm->cfg->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
os_free(buf);
goto fail;
@@ -171,8 +171,8 @@ static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_psk_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_psk_data *data = priv;
size_t len;
@@ -182,7 +182,7 @@ static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
- return TRUE;
+ return true;
}
t = EAP_PSK_FLAGS_GET_T(*pos);
@@ -191,22 +191,22 @@ static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
if (data->state == PSK_1 && t != 1) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
"ignore T=%d", t);
- return TRUE;
+ return true;
}
if (data->state == PSK_3 && t != 3) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
"ignore T=%d", t);
- return TRUE;
+ return true;
}
if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
(t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -293,7 +293,7 @@ static void eap_psk_process_2(struct eap_sm *sm,
os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
- buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
+ buflen = data->id_p_len + sm->cfg->server_id_len + 2 * EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL) {
data->state = FAILURE;
@@ -301,8 +301,8 @@ static void eap_psk_process_2(struct eap_sm *sm,
}
os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- os_memcpy(pos, sm->server_id, sm->server_id_len);
- pos += sm->server_id_len;
+ os_memcpy(pos, sm->cfg->server_id, sm->cfg->server_id_len);
+ pos += sm->cfg->server_id_len;
os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
@@ -433,7 +433,7 @@ static void eap_psk_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
+static bool eap_psk_isDone(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -474,7 +474,7 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_psk_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_pwd.c b/contrib/wpa/src/eap_server/eap_server_pwd.c
index a8087c1d8a63..81cddca607f5 100644
--- a/contrib/wpa/src/eap_server/eap_server_pwd.c
+++ b/contrib/wpa/src/eap_server/eap_server_pwd.c
@@ -97,7 +97,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
- data->group_num = sm->pwd_group;
+ data->group_num = sm->cfg->pwd_group;
wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
data->group_num);
data->state = PWD_ID_Req;
@@ -134,7 +134,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
/* use default MTU from RFC 5931 if not configured otherwise */
- data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
+ data->mtu = sm->cfg->fragment_size > 0 ? sm->cfg->fragment_size : 1020;
return data;
}
@@ -530,8 +530,8 @@ eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_pwd_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_pwd_data *data = priv;
const u8 *pos;
@@ -540,7 +540,7 @@ static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
@@ -548,20 +548,20 @@ static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
if (data->state == PWD_ID_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
- return FALSE;
+ return false;
if (data->state == PWD_Commit_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
- return FALSE;
+ return false;
if (data->state == PWD_Confirm_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
*pos, data->state);
- return TRUE;
+ return true;
}
@@ -1003,14 +1003,14 @@ static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
+static bool eap_pwd_is_success(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return data->state == SUCCESS;
}
-static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
+static bool eap_pwd_is_done(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return (data->state == SUCCESS) || (data->state == FAILURE);
diff --git a/contrib/wpa/src/eap_server/eap_server_sake.c b/contrib/wpa/src/eap_server/eap_server_sake.c
index 2fc2c0575a94..8c39e63b9242 100644
--- a/contrib/wpa/src/eap_server/eap_server_sake.c
+++ b/contrib/wpa/src/eap_server/eap_server_sake.c
@@ -123,7 +123,7 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
plen = 4;
- plen += 2 + sm->server_id_len;
+ plen += 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
if (msg == NULL) {
data->state = FAILURE;
@@ -135,7 +135,7 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -158,7 +158,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
data->rand_s, EAP_SAKE_RAND_LEN);
- plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
+ plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
if (msg == NULL) {
data->state = FAILURE;
@@ -171,7 +171,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -198,7 +198,7 @@ static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 0,
wpabuf_head(msg), wpabuf_len(msg), mic, mic))
{
@@ -232,8 +232,8 @@ static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_sake_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_sake_data *data = priv;
struct eap_sake_hdr *resp;
@@ -244,7 +244,7 @@ static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
- return TRUE;
+ return true;
}
resp = (struct eap_sake_hdr *) pos;
@@ -254,33 +254,33 @@ static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
if (version != EAP_SAKE_VERSION) {
wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
- return TRUE;
+ return true;
}
if (session_id != data->session_id) {
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
session_id, data->session_id);
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
- return FALSE;
+ return false;
if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
- return FALSE;
+ return false;
if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
- return FALSE;
+ return false;
if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
subtype, data->state);
- return TRUE;
+ return true;
}
@@ -351,7 +351,7 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
@@ -392,7 +392,7 @@ static void eap_sake_process_confirm(struct eap_sm *sm,
}
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p) < 0) {
@@ -456,7 +456,7 @@ static void eap_sake_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
+static bool eap_sake_isDone(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -497,7 +497,7 @@ static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_sake_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_sim.c b/contrib/wpa/src/eap_server/eap_server_sim.c
index 5243568e71d0..8a6828962079 100644
--- a/contrib/wpa/src/eap_server/eap_server_sim.c
+++ b/contrib/wpa/src/eap_server/eap_server_sim.c
@@ -76,7 +76,7 @@ static void * eap_sim_init(struct eap_sm *sm)
{
struct eap_sim_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
return NULL;
}
@@ -150,24 +150,24 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (!(sm->eap_sim_id & 0x01)) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
/* Use of pseudonyms disabled in configuration */
data->next_pseudonym = NULL;
} else if (!nonce_s) {
data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
/* Do not update pseudonym during re-authentication */
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (!(sm->eap_sim_id & 0x02)) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
/* Use of fast reauth disabled in configuration */
data->next_reauth_id = NULL;
} else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
@@ -240,7 +240,7 @@ static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -279,7 +279,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -360,8 +360,8 @@ static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_sim_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -369,55 +369,55 @@ static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
- u8 subtype)
+static bool eap_sim_unexpected_subtype(struct eap_sim_data *data,
+ u8 subtype)
{
if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
- return FALSE;
+ return false;
switch (data->state) {
case START:
if (subtype != EAP_SIM_SUBTYPE_START) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case CHALLENGE:
if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case REAUTH:
if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case NOTIFICATION:
if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
default:
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
"processing a response", data->state);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -475,7 +475,7 @@ static void eap_sim_process_start(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
username);
data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
@@ -497,7 +497,7 @@ static void eap_sim_process_start(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
@@ -538,7 +538,7 @@ skip_id_update:
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
+ sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -599,7 +599,7 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -607,12 +607,13 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
eap_sim_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -672,7 +673,7 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -680,12 +681,13 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
eap_sim_state(data, SUCCESS);
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -694,7 +696,7 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_sim_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
@@ -792,7 +794,7 @@ static void eap_sim_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
+static bool eap_sim_isDone(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -831,7 +833,7 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_sim_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_teap.c b/contrib/wpa/src/eap_server/eap_server_teap.c
index d8e5414d4563..691b44a8d346 100644
--- a/contrib/wpa/src/eap_server/eap_server_teap.c
+++ b/contrib/wpa/src/eap_server/eap_server_teap.c
@@ -31,7 +31,7 @@ struct eap_teap_data {
enum {
START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
- FAILURE_SEND_RESULT, SUCCESS, FAILURE
+ FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
} state;
u8 teap_version;
@@ -56,12 +56,15 @@ struct eap_teap_data {
size_t srv_id_len;
char *srv_id_info;
+ unsigned int basic_auth_not_done:1;
+ unsigned int inner_eap_not_done:1;
int anon_provisioning;
+ int skipped_inner_auth;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
struct wpabuf *peer_outer_tlvs;
- u8 *identity; /* from PAC-Opaque */
+ u8 *identity; /* from PAC-Opaque or client certificate */
size_t identity_len;
int eap_seq;
int tnc_started;
@@ -70,6 +73,7 @@ struct eap_teap_data {
int pac_key_refresh_time;
enum teap_error_codes error_code;
+ enum teap_identity_types cur_id_type;
};
@@ -100,6 +104,8 @@ static const char * eap_teap_state_txt(int state)
return "REQUEST_PAC";
case FAILURE_SEND_RESULT:
return "FAILURE_SEND_RESULT";
+ case SUCCESS_SEND_RESULT:
+ return "SUCCESS_SEND_RESULT";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -119,8 +125,8 @@ static void eap_teap_state(struct eap_teap_data *data, int state)
}
-static EapType eap_teap_req_failure(struct eap_teap_data *data,
- enum teap_error_codes error)
+static enum eap_type eap_teap_req_failure(struct eap_teap_data *data,
+ enum teap_error_codes error)
{
eap_teap_state(data, FAILURE_SEND_RESULT);
return EAP_TYPE_NONE;
@@ -285,7 +291,7 @@ static int eap_teap_derive_key_auth(struct eap_sm *sm,
int res;
/* RFC 7170, Section 5.1 */
- res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
+ res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
data->simck_msk, EAP_TEAP_SIMCK_LEN);
if (res)
@@ -308,8 +314,9 @@ static int eap_teap_update_icmk(struct eap_sm *sm, struct eap_teap_data *data)
wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)",
data->simck_idx + 1);
- if (sm->eap_teap_auth == 1)
- return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ if (sm->cfg->eap_teap_auth == 1)
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
if (!data->phase2_method || !data->phase2_priv) {
@@ -332,7 +339,8 @@ static int eap_teap_update_icmk(struct eap_sm *sm, struct eap_teap_data *data)
&emsk_len);
}
- res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
msk, msk_len, emsk, emsk_len,
data->simck_msk, data->cmk_msk,
data->simck_emsk, data->cmk_emsk);
@@ -357,7 +365,9 @@ static void * eap_teap_init(struct eap_sm *sm)
data->teap_version = EAP_TEAP_VERSION;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_TEAP)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl,
+ sm->cfg->eap_teap_auth == 2 ? 2 : 0,
+ EAP_TYPE_TEAP)) {
wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL.");
eap_teap_reset(sm, data);
return NULL;
@@ -366,7 +376,8 @@ static void * eap_teap_init(struct eap_sm *sm)
/* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
* enforce inner EAP with mutual authentication to be used) */
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_teap_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO,
@@ -375,48 +386,49 @@ static void * eap_teap_init(struct eap_sm *sm)
return NULL;
}
- if (!sm->pac_opaque_encr_key) {
+ if (!sm->cfg->pac_opaque_encr_key) {
wpa_printf(MSG_INFO,
"EAP-TEAP: No PAC-Opaque encryption key configured");
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (!sm->eap_fast_a_id) {
+ if (!sm->cfg->eap_fast_a_id) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id = os_malloc(sm->eap_fast_a_id_len);
+ data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len);
if (!data->srv_id) {
eap_teap_reset(sm, data);
return NULL;
}
- os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
- data->srv_id_len = sm->eap_fast_a_id_len;
+ os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (!sm->eap_fast_a_id_info) {
+ if (!sm->cfg->eap_fast_a_id_info) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured");
eap_teap_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (!data->srv_id_info) {
eap_teap_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -492,12 +504,25 @@ static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
+ if (!data->identity && sm->cfg->eap_teap_auth == 2) {
+ const char *subject;
+
+ subject = tls_connection_get_peer_subject(data->ssl.conn);
+ if (subject) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer subject from Phase 1 client certificate: '%s'",
+ subject);
+ data->identity = (u8 *) os_strdup(subject);
+ data->identity_len = os_strlen(subject);
+ }
+ }
+
data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn);
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Failed to get cipher information");
eap_teap_state(data, FAILURE);
@@ -523,30 +548,65 @@ static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm,
struct eap_teap_data *data,
u8 id)
{
- struct wpabuf *req;
+ struct wpabuf *req, *id_tlv = NULL;
+
+ if (sm->cfg->eap_teap_auth == 1 ||
+ (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_IDENTITY)) {
+ switch (sm->cfg->eap_teap_id) {
+ case EAP_TEAP_ID_ALLOW_ANY:
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER:
+ case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_MACHINE:
+ case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
+ if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ else
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ }
+ }
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
+ data->basic_auth_not_done = 1;
req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0);
- return req;
+ return wpabuf_concat(req, id_tlv);
}
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
+ data->inner_eap_not_done = 1;
if (!data->phase2_priv) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Phase 2 method not initialized");
+ wpabuf_free(id_tlv);
return NULL;
}
req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
- if (!req)
+ if (!req) {
+ wpabuf_free(id_tlv);
return NULL;
+ }
wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req);
- return eap_teap_tlv_eap_payload(req);
+
+ return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv);
}
@@ -563,12 +623,14 @@ static struct wpabuf * eap_teap_build_crypto_binding(
return NULL;
if (data->send_new_pac || data->anon_provisioning ||
- data->phase2_method)
+ data->basic_auth_not_done || data->inner_eap_not_done ||
+ data->phase2_method || sm->cfg->eap_teap_separate_result)
data->final_result = 0;
else
data->final_result = 1;
- if (!data->final_result || data->eap_seq > 0) {
+ if (!data->final_result || data->eap_seq > 0 ||
+ sm->cfg->eap_teap_auth == 1) {
/* Intermediate-Result */
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
@@ -842,7 +904,8 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id)
case START:
return eap_teap_build_start(sm, data, id);
case PHASE1B:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_teap_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -899,6 +962,10 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id)
req = wpabuf_concat(
req, eap_teap_tlv_error(data->error_code));
break;
+ case SUCCESS_SEND_RESULT:
+ req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
+ data->final_result = 1;
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
__func__, data->state);
@@ -913,8 +980,8 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_teap_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_teap_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -922,23 +989,22 @@ static Boolean eap_teap_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len);
if (!pos || len < 1) {
wpa_printf(MSG_INFO, "EAP-TEAP: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -950,11 +1016,33 @@ static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
}
+static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
+ enum teap_identity_types id_type)
+{
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_USER)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
+ id_type != data->cur_id_type)
+ return 0;
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
+ id_type != TEAP_IDENTITY_TYPE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ return 1;
+}
+
+
static void eap_teap_process_phase2_response(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -982,8 +1070,9 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Peer Nak'ed required TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -991,14 +1080,17 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, 0);
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1018,17 +1110,26 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
return;
}
switch (data->state) {
case PHASE2_ID:
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ break;
+ }
if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_teap_req_failure(
data, TEAP_ERROR_INNER_METHOD);
break;
@@ -1039,23 +1140,33 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
/* TODO: Allow any inner EAP method that provides
* mutual authentication and EMSK derivation (i.e.,
* EAP-pwd or EAP-EKE). */
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_PWD;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_teap_update_icmk(sm, data);
+ if (data->state == PHASE2_METHOD &&
+ (sm->cfg->eap_teap_id !=
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
+ data->inner_eap_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1069,13 +1180,14 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
break;
}
- eap_teap_phase2_init(sm, data, next_type);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
static void eap_teap_process_phase2_eap(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
struct eap_hdr *hdr;
size_t len;
@@ -1102,7 +1214,8 @@ static void eap_teap_process_phase2_eap(struct eap_sm *sm,
(unsigned long) len);
switch (hdr->code) {
case EAP_CODE_RESPONSE:
- eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len);
+ eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len,
+ id_type);
break;
default:
wpa_printf(MSG_INFO,
@@ -1115,11 +1228,20 @@ static void eap_teap_process_phase2_eap(struct eap_sm *sm,
static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
struct eap_teap_data *data,
- u8 *in_data, size_t in_len)
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
{
u8 *pos, *end, *username, *password, *new_id;
u8 userlen, passlen;
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
pos = in_data;
end = pos + in_len;
@@ -1197,6 +1319,9 @@ static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
sm->identity = new_id;
sm->identity_len = userlen;
}
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
+ data->basic_auth_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING);
eap_teap_update_icmk(sm, data);
}
@@ -1444,7 +1569,8 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
return;
}
- if (!data->final_result &&
+ if (sm->cfg->eap_teap_auth != 1 &&
+ !data->skipped_inner_auth &&
tlv.iresult != TEAP_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Crypto-Binding TLV without intermediate Success Result");
@@ -1466,16 +1592,16 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
eap_teap_state(data, FAILURE);
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
eap_teap_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1496,30 +1622,55 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Server triggered re-keying of Tunnel PAC");
eap_teap_state(data, REQUEST_PAC);
- } else if (data->final_result)
+ } else if (data->final_result) {
eap_teap_state(data, SUCCESS);
+ } else if (sm->cfg->eap_teap_separate_result) {
+ eap_teap_state(data, SUCCESS_SEND_RESULT);
+ }
}
if (tlv.basic_auth_resp) {
- if (sm->eap_teap_auth != 1) {
+ if (sm->cfg->eap_teap_auth != 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp,
- tlv.basic_auth_resp_len);
+ tlv.basic_auth_resp_len,
+ tlv.identity_type);
}
if (tlv.eap_payload_tlv) {
- if (sm->eap_teap_auth == 1) {
+ if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth");
eap_teap_state(data, FAILURE);
return;
}
eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
- tlv.eap_payload_tlv_len);
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
+ }
+
+ if (data->state == SUCCESS_SEND_RESULT &&
+ tlv.result == TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer agreed with final success - authentication completed");
+ eap_teap_state(data, SUCCESS);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with basic password authentication for second credential");
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with inner EAP authentication for second credential");
+ eap_teap_state(data, PHASE2_ID);
+ if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0)
+ eap_teap_state(data, FAILURE);
}
}
@@ -1544,7 +1695,7 @@ static void eap_teap_process_phase2(struct eap_sm *sm,
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (!in_decrypted) {
wpa_printf(MSG_INFO,
@@ -1605,7 +1756,7 @@ static int eap_teap_process_phase1(struct eap_sm *sm,
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1622,7 +1773,8 @@ static int eap_teap_process_phase1(struct eap_sm *sm,
static int eap_teap_process_phase2_start(struct eap_sm *sm,
struct eap_teap_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
/* Used PAC and identity is from PAC-Opaque */
@@ -1635,38 +1787,44 @@ static int eap_teap_process_phase2_start(struct eap_sm *sm,
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-TEAP: Phase 2 Identity not found in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->eap_teap_pac_no_inner) {
+ } else if (sm->cfg->eap_teap_pac_no_inner ||
+ sm->cfg->eap_teap_auth == 2) {
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth");
+ data->skipped_inner_auth = 1;
/* FIX: Need to derive CMK here. However, how is that
* supposed to be done? RFC 7170 does not tell that for
* the no-inner-auth case. */
- eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
+ eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
data->cmk_msk);
eap_teap_state(data, CRYPTO_BINDING);
return 1;
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 1;
} else {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Identity already known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
eap_teap_state(data, PHASE2_METHOD);
}
- } else if (sm->eap_teap_auth == 1) {
+ } else if (sm->cfg->eap_teap_auth == 1) {
eap_teap_state(data, PHASE2_BASIC_AUTH);
return 0;
} else {
eap_teap_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_teap_phase2_init(sm, data, next_type);
+ return eap_teap_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1690,6 +1848,7 @@ static void eap_teap_process_msg(struct eap_sm *sm, void *priv,
case PHASE2_METHOD:
case CRYPTO_BINDING:
case REQUEST_PAC:
+ case SUCCESS_SEND_RESULT:
eap_teap_process_phase2(sm, data, data->ssl.tls_in);
break;
case FAILURE_SEND_RESULT:
@@ -1831,7 +1990,7 @@ static void eap_teap_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_teap_isDone(struct eap_sm *sm, void *priv)
+static bool eap_teap_isDone(struct eap_sm *sm, void *priv)
{
struct eap_teap_data *data = priv;
@@ -1853,7 +2012,8 @@ static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len)
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_msk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
@@ -1877,7 +2037,8 @@ static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
* is used in this derivation */
- if (eap_teap_derive_eap_emsk(data->simck_msk, eapKeyData) < 0) {
+ if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
}
@@ -1887,7 +2048,7 @@ static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_teap_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_teap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_teap_data *data = priv;
diff --git a/contrib/wpa/src/eap_server/eap_server_tls.c b/contrib/wpa/src/eap_server/eap_server_tls.c
index 0712d4ccd5aa..00a496f2c61f 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls.c
@@ -58,7 +58,7 @@ static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1);
@@ -187,7 +187,8 @@ static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn))
data->established = 1;
break;
default:
@@ -225,8 +226,8 @@ check_established:
}
-static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_tls_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_tls_data *data = priv;
const u8 *pos;
@@ -245,10 +246,10 @@ static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -265,39 +266,6 @@ static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
eap_tls_state(data, FAILURE);
return;
}
-
- if (data->ssl.tls_v13 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- struct wpabuf *plain, *encr;
-
- wpa_printf(MSG_DEBUG,
- "EAP-TLS: Send empty application data to indicate end of exchange");
- /* FIX: This should be an empty application data based on
- * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
- * length payload (SSL_write() documentation explicitly
- * describes this as not allowed), so work around that for now
- * by sending out a payload of one octet. Hopefully the draft
- * specification will change to allow this so that no crypto
- * library changes are needed. */
- plain = wpabuf_alloc(1);
- if (!plain)
- return;
- wpabuf_put_u8(plain, 0);
- encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
- wpabuf_free(plain);
- if (!encr)
- return;
- if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
- wpa_printf(MSG_INFO,
- "EAP-TLS: Failed to resize output buffer");
- wpabuf_free(encr);
- return;
- }
- wpabuf_put_buf(data->ssl.tls_out, encr);
- wpa_hexdump_buf(MSG_DEBUG,
- "EAP-TLS: Data appended to the message", encr);
- wpabuf_free(encr);
- }
}
@@ -315,8 +283,8 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -345,7 +313,7 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
+static bool eap_tls_isDone(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -430,7 +398,7 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_tls_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_tls_common.c b/contrib/wpa/src/eap_server/eap_server_tls_common.c
index 907101c7e2e3..a9b53b1a0654 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls_common.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls_common.c
@@ -18,7 +18,7 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -47,9 +47,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type)
{
u8 session_ctx[8];
- unsigned int flags = sm->tls_flags;
+ unsigned int flags = sm->cfg->tls_flags;
- if (sm->ssl_ctx == NULL) {
+ if (!sm->cfg->ssl_ctx) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
return -1;
}
@@ -57,7 +57,7 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
data->eap = sm;
data->phase2 = sm->init_phase2;
- data->conn = tls_connection_init(sm->ssl_ctx);
+ data->conn = tls_connection_init(sm->cfg->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
@@ -75,17 +75,18 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
flags |= TLS_CONN_DISABLE_SESSION_TICKET;
os_memcpy(session_ctx, "hostapd", 7);
session_ctx[7] = (u8) eap_type;
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer,
flags, session_ctx,
sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
}
- data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
+ data->tls_out_limit = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : 1398;
if (data->phase2) {
/* Limit the fragment size in the inner TLS authentication
* since the outer authentication with EAP-PEAP does not yet
@@ -99,7 +100,7 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
eap_server_tls_free_in_buf(data);
wpabuf_free(data->tls_out);
data->tls_out = NULL;
@@ -116,7 +117,7 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
if (out == NULL)
return NULL;
- if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ if (tls_connection_export_key(sm->cfg->ssl_ctx, data->conn, label,
context, context_len, out, len)) {
os_free(out);
return NULL;
@@ -145,10 +146,10 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
{
struct tls_random keys;
u8 *out;
- const u8 context[] = { EAP_TYPE_TLS };
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
@@ -170,7 +171,7 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
return id;
}
- if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_random(sm->cfg->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL)
@@ -340,29 +341,80 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
WPA_ASSERT(data->tls_out == NULL);
}
- data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
+ data->tls_out = tls_connection_server_handshake(sm->cfg->ssl_ctx,
data->conn,
data->tls_in, NULL);
if (data->tls_out == NULL) {
wpa_printf(MSG_INFO, "SSL: TLS processing failed");
return -1;
}
- if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ if (tls_connection_get_failed(sm->cfg->ssl_ctx, data->conn)) {
/* TLS processing has failed - return error */
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
return -1;
}
- if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ if (tls_get_version(sm->cfg->ssl_ctx, data->conn,
+ buf, sizeof(buf)) == 0) {
wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
}
if (!sm->serial_num &&
- tls_connection_established(sm->ssl_ctx, data->conn))
- sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
- data->conn);
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(
+ sm->cfg->ssl_ctx, data->conn);
+
+ /*
+ * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+ *
+ * We need to signal the other end that TLS negotiation is done. We
+ * can't send a zero-length application data message, so we send
+ * application data which is one byte of zero.
+ *
+ * Note this is only done for when there is no application data to be
+ * sent. So this is done always for EAP-TLS but notibly not for PEAP
+ * even on resumption.
+ */
+ if (data->tls_v13 &&
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn)) {
+ struct wpabuf *plain, *encr;
+
+ switch (sm->currentMethod) {
+ case EAP_TYPE_PEAP:
+ break;
+ default:
+ if (!tls_connection_resumed(sm->cfg->ssl_ctx,
+ data->conn))
+ break;
+ /* fallthrough */
+ case EAP_TYPE_TLS:
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Send Commitment Message");
+
+ plain = wpabuf_alloc(1);
+ if (!plain)
+ return -1;
+ wpabuf_put_u8(plain, 0);
+ encr = eap_server_tls_encrypt(sm, data, plain);
+ wpabuf_free(plain);
+ if (!encr)
+ return -1;
+ if (wpabuf_resize(&data->tls_out, wpabuf_len(encr)) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "EAP-TLS: Failed to resize output buffer");
+ wpabuf_free(encr);
+ return -1;
+ }
+ wpabuf_put_buf(data->tls_out, encr);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Data appended to the message",
+ encr);
+ wpabuf_free(encr);
+ }
+ }
return 0;
}
@@ -451,8 +503,7 @@ struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
{
struct wpabuf *buf;
- buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
- plain);
+ buf = tls_connection_encrypt(sm->cfg->ssl_ctx, data->conn, plain);
if (buf == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
return NULL;
@@ -506,7 +557,7 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
if (proc_msg)
proc_msg(sm, priv, respData);
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+ if (tls_connection_get_write_alerts(sm->cfg->ssl_ctx, data->conn) > 1) {
wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
"TLS processing");
res = -1;
diff --git a/contrib/wpa/src/eap_server/eap_server_tnc.c b/contrib/wpa/src/eap_server/eap_server_tnc.c
index b568558fd42e..36fb5c34d9c4 100644
--- a/contrib/wpa/src/eap_server/eap_server_tnc.c
+++ b/contrib/wpa/src/eap_server/eap_server_tnc.c
@@ -84,8 +84,8 @@ static void * eap_tnc_init(struct eap_sm *sm)
return NULL;
}
- data->fragment_size = sm->fragment_size > 100 ?
- sm->fragment_size - 98 : 1300;
+ data->fragment_size = sm->cfg->fragment_size > 100 ?
+ sm->cfg->fragment_size - 98 : 1300;
return data;
}
@@ -320,8 +320,8 @@ static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_tnc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_tnc_data *data = priv;
const u8 *pos;
@@ -331,29 +331,29 @@ static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
&len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
- return TRUE;
+ return true;
}
if (len == 0 && data->state != WAIT_FRAG_ACK) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
- return TRUE;
+ return true;
}
if (len == 0)
- return FALSE; /* Fragment ACK does not include flags */
+ return false; /* Fragment ACK does not include flags */
if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
*pos & EAP_TNC_VERSION_MASK);
- return TRUE;
+ return true;
}
if (*pos & EAP_TNC_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -508,7 +508,7 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv,
eap_tnc_set_state(data, FAIL);
return;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
if (eap_tnc_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
@@ -537,14 +537,14 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_tnc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_tnc_data *data = priv;
return data->state == DONE || data->state == FAIL;
}
-static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_tnc_data *data = priv;
return data->state == DONE;
diff --git a/contrib/wpa/src/eap_server/eap_server_ttls.c b/contrib/wpa/src/eap_server/eap_server_ttls.c
index 52bff8afe42d..b89352244148 100644
--- a/contrib/wpa/src/eap_server/eap_server_ttls.c
+++ b/contrib/wpa/src/eap_server/eap_server_ttls.c
@@ -81,7 +81,7 @@ static void eap_ttls_valid_session(struct eap_sm *sm,
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -480,7 +480,8 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
"starting Phase2");
eap_ttls_state(data, PHASE2_START);
@@ -508,8 +509,8 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_ttls_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -517,10 +518,10 @@ static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -827,15 +828,14 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
struct eap_ttls_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -850,7 +850,8 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
struct eap_ttls_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -875,14 +876,17 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
- next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
- "initialize EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
return;
}
@@ -930,12 +934,16 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
}
eap_ttls_state(data, PHASE2_METHOD);
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
- "EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
}
break;
@@ -962,8 +970,8 @@ static void eap_ttls_process_phase2_eap(struct eap_sm *sm,
if (data->state == PHASE2_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
- {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
"initialize EAP-Identity");
return;
@@ -1022,7 +1030,7 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
@@ -1112,11 +1120,11 @@ done:
static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
{
#ifdef EAP_SERVER_TNC
- if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+ if (!sm->cfg->tnc || data->state != SUCCESS || data->tnc_started)
return;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF, EAP_TYPE_TNC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
eap_ttls_state(data, FAILURE);
return;
@@ -1202,8 +1210,8 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -1252,7 +1260,7 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isDone(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1263,13 +1271,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
- EAP_TLS_KEY_LEN);
+ label, context, context_len,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
@@ -1282,7 +1302,7 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->state == SUCCESS;
@@ -1305,12 +1325,24 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/contrib/wpa/src/eap_server/eap_server_vendor_test.c b/contrib/wpa/src/eap_server/eap_server_vendor_test.c
index 96399775945b..77860411b77b 100644
--- a/contrib/wpa/src/eap_server/eap_server_vendor_test.c
+++ b/contrib/wpa/src/eap_server/eap_server_vendor_test.c
@@ -88,8 +88,8 @@ static struct wpabuf * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv,
}
-static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_vendor_test_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -97,10 +97,10 @@ static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -130,7 +130,7 @@ static void eap_vendor_test_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
@@ -158,7 +158,7 @@ static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
-static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
diff --git a/contrib/wpa/src/eap_server/eap_server_wsc.c b/contrib/wpa/src/eap_server/eap_server_wsc.c
index 4a5cb980afac..a162deb9ef6b 100644
--- a/contrib/wpa/src/eap_server/eap_server_wsc.c
+++ b/contrib/wpa/src/eap_server/eap_server_wsc.c
@@ -103,10 +103,10 @@ static void * eap_wsc_init(struct eap_sm *sm)
data->registrar = registrar;
os_memset(&cfg, 0, sizeof(cfg));
- cfg.wps = sm->wps;
+ cfg.wps = sm->cfg->wps;
cfg.registrar = registrar;
if (registrar) {
- if (sm->wps == NULL || sm->wps->registrar == NULL) {
+ if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
"initialized");
os_free(data);
@@ -132,20 +132,22 @@ static void * eap_wsc_init(struct eap_sm *sm)
cfg.peer_addr = sm->peer_addr;
#ifdef CONFIG_P2P
if (sm->assoc_p2p_ie) {
- wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
- "client");
- cfg.use_psk_key = 1;
+ if (!sm->cfg->wps->use_passphrase) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-WSC: Prefer PSK format for non-6 GHz P2P client");
+ cfg.use_psk_key = 1;
+ }
cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
}
#endif /* CONFIG_P2P */
- cfg.pbc_in_m1 = sm->pbc_in_m1;
+ cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
return NULL;
}
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- WSC_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
return data;
}
@@ -270,8 +272,8 @@ static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
-static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_wsc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -280,10 +282,10 @@ static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
respData, &len);
if (pos == NULL || len < 2) {
wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -462,17 +464,17 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv,
}
-static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_wsc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_wsc_data *data = priv;
return data->state == FAIL;
}
-static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
{
/* EAP-WSC will always result in EAP-Failure */
- return FALSE;
+ return false;
}
diff --git a/contrib/wpa/src/eap_server/eap_tls_common.h b/contrib/wpa/src/eap_server/eap_tls_common.h
index 74b1c728d681..b0b736123016 100644
--- a/contrib/wpa/src/eap_server/eap_tls_common.h
+++ b/contrib/wpa/src/eap_server/eap_tls_common.h
@@ -73,7 +73,7 @@ struct eap_ssl_data {
#define EAP_WFA_UNAUTH_TLS_TYPE 254
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type);
diff --git a/contrib/wpa/src/eap_server/tncs.c b/contrib/wpa/src/eap_server/tncs.c
index 942a195761ac..4a30486f7792 100644
--- a/contrib/wpa/src/eap_server/tncs.c
+++ b/contrib/wpa/src/eap_server/tncs.c
@@ -179,7 +179,7 @@ static TNC_Result TNC_TNCS_SendMessage(
TNC_MessageType messageType)
{
struct tncs_data *tncs;
- unsigned char *b64;
+ char *b64;
size_t b64len;
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
@@ -678,8 +678,7 @@ static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
return NULL;
*pos2 = '\0';
- decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
- decoded_len);
+ decoded = base64_decode(pos, os_strlen(pos), decoded_len);
*pos2 = '<';
if (decoded == NULL) {
wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
diff --git a/contrib/wpa/src/eapol_auth/Makefile b/contrib/wpa/src/eapol_auth/Makefile
new file mode 100644
index 000000000000..c82042f437b2
--- /dev/null
+++ b/contrib/wpa/src/eapol_auth/Makefile
@@ -0,0 +1,2 @@
+LIB_OBJS = eapol_auth_sm.o eapol_auth_dump.o
+include ../lib.rules
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
index 7206d32d7391..1c11cb613bd5 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
@@ -56,6 +56,7 @@ static void eapol_auth_logger(struct eapol_authenticator *eapol,
}
+PRINTF_FORMAT(4, 5)
static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
const u8 *addr, eapol_logger_level level,
const char *fmt, ...)
@@ -206,10 +207,10 @@ SM_STATE(AUTH_PAE, INITIALIZE)
* get here on disconnection event without advancing to the
* AUTHENTICATING state to clear keyRun before the IEEE 802.11 RSN
* authenticator state machine runs and that may advance from
- * AUTHENTICATION2 to INITPMK if keyRun = TRUE has been left from the
+ * AUTHENTICATION2 to INITPMK if keyRun = true has been left from the
* last association. This can be avoided by clearing keyRun here.
*/
- sm->keyRun = FALSE;
+ sm->keyRun = false;
}
@@ -229,7 +230,7 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->reAuthCount = 0;
- sm->eapolLogoff = FALSE;
+ sm->eapolLogoff = false;
if (!from_initialize) {
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
sm->flags & EAPOL_SM_PREAUTH,
@@ -251,7 +252,7 @@ SM_STATE(AUTH_PAE, RESTART)
SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
- sm->eap_if->eapRestart = TRUE;
+ sm->eap_if->eapRestart = true;
}
@@ -262,7 +263,7 @@ SM_STATE(AUTH_PAE, CONNECTING)
SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
- sm->reAuthenticate = FALSE;
+ sm->reAuthenticate = false;
sm->reAuthCount++;
}
@@ -277,7 +278,7 @@ SM_STATE(AUTH_PAE, HELD)
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->quietWhile = sm->quietPeriod;
- sm->eapolLogoff = FALSE;
+ sm->eapolLogoff = false;
eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
"authentication failed - EAP type: %d (%s)",
@@ -324,13 +325,13 @@ SM_STATE(AUTH_PAE, AUTHENTICATING)
{
SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
- sm->eapolStart = FALSE;
- sm->authSuccess = FALSE;
- sm->authFail = FALSE;
- sm->authTimeout = FALSE;
- sm->authStart = TRUE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
+ sm->eapolStart = false;
+ sm->authSuccess = false;
+ sm->authFail = false;
+ sm->authTimeout = false;
+ sm->authStart = true;
+ sm->keyRun = false;
+ sm->keyDone = false;
}
@@ -347,9 +348,9 @@ SM_STATE(AUTH_PAE, ABORTING)
SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
- sm->authAbort = TRUE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
+ sm->authAbort = true;
+ sm->keyRun = false;
+ sm->keyDone = false;
}
@@ -360,7 +361,7 @@ SM_STATE(AUTH_PAE, FORCE_AUTH)
sm->authPortStatus = Authorized;
setPortAuthorized();
sm->portMode = ForceAuthorized;
- sm->eapolStart = FALSE;
+ sm->eapolStart = false;
txCannedSuccess();
}
@@ -372,7 +373,7 @@ SM_STATE(AUTH_PAE, FORCE_UNAUTH)
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->portMode = ForceUnauthorized;
- sm->eapolStart = FALSE;
+ sm->eapolStart = false;
txCannedFail();
}
@@ -457,8 +458,8 @@ SM_STATE(BE_AUTH, INITIALIZE)
SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
abortAuth();
- sm->eap_if->eapNoReq = FALSE;
- sm->authAbort = FALSE;
+ sm->eap_if->eapNoReq = false;
+ sm->authAbort = false;
}
@@ -467,7 +468,7 @@ SM_STATE(BE_AUTH, REQUEST)
SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
txReq();
- sm->eap_if->eapReq = FALSE;
+ sm->eap_if->eapReq = false;
sm->backendOtherRequestsToSupplicant++;
/*
@@ -481,7 +482,7 @@ SM_STATE(BE_AUTH, REQUEST)
* EAP-Request from the main EAP method. This can be avoided by
* clearing eapolEap here.
*/
- sm->eapolEap = FALSE;
+ sm->eapolEap = false;
}
@@ -489,11 +490,11 @@ SM_STATE(BE_AUTH, RESPONSE)
{
SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
- sm->authTimeout = FALSE;
- sm->eapolEap = FALSE;
- sm->eap_if->eapNoReq = FALSE;
+ sm->authTimeout = false;
+ sm->eapolEap = false;
+ sm->eap_if->eapNoReq = false;
sm->aWhile = sm->serverTimeout;
- sm->eap_if->eapResp = TRUE;
+ sm->eap_if->eapResp = true;
/* sendRespToServer(); */
sm->backendResponses++;
}
@@ -504,8 +505,8 @@ SM_STATE(BE_AUTH, SUCCESS)
SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
txReq();
- sm->authSuccess = TRUE;
- sm->keyRun = TRUE;
+ sm->authSuccess = true;
+ sm->keyRun = true;
}
@@ -514,7 +515,7 @@ SM_STATE(BE_AUTH, FAIL)
SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
txReq();
- sm->authFail = TRUE;
+ sm->authFail = true;
}
@@ -522,7 +523,7 @@ SM_STATE(BE_AUTH, TIMEOUT)
{
SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
- sm->authTimeout = TRUE;
+ sm->authTimeout = true;
}
@@ -530,7 +531,7 @@ SM_STATE(BE_AUTH, IDLE)
{
SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
- sm->authStart = FALSE;
+ sm->authStart = false;
}
@@ -538,7 +539,7 @@ SM_STATE(BE_AUTH, IGNORE)
{
SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
- sm->eap_if->eapNoReq = FALSE;
+ sm->eap_if->eapNoReq = false;
}
@@ -621,7 +622,7 @@ SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
{
SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
- sm->reAuthenticate = TRUE;
+ sm->reAuthenticate = true;
sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
EAPOL_AUTH_REAUTHENTICATE);
}
@@ -648,6 +649,8 @@ SM_STEP(REAUTH_TIMER)
+#ifdef CONFIG_WEP
+
/* Authenticator Key Transmit state machine */
SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
@@ -661,8 +664,8 @@ SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
txKey();
- sm->eap_if->eapKeyAvailable = FALSE;
- sm->keyDone = TRUE;
+ sm->eap_if->eapKeyAvailable = false;
+ sm->keyDone = true;
}
@@ -703,7 +706,7 @@ SM_STATE(KEY_RX, KEY_RECEIVE)
SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
processKey();
- sm->rxKey = FALSE;
+ sm->rxKey = false;
}
@@ -726,6 +729,8 @@ SM_STEP(KEY_RX)
}
}
+#endif /* CONFIG_WEP */
+
/* Controlled Directions state machine */
@@ -775,7 +780,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
if (eapol == NULL)
return NULL;
@@ -803,7 +808,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
sm->reAuthPeriod = eapol->conf.eap_reauth_period;
- sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
+ sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0;
sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
@@ -813,46 +818,24 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
sm->portControl = Auto;
+#ifdef CONFIG_WEP
if (!eapol->conf.wpa &&
(eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
- sm->keyTxEnabled = TRUE;
+ sm->keyTxEnabled = true;
else
- sm->keyTxEnabled = FALSE;
+#endif /* CONFIG_WEP */
+ sm->keyTxEnabled = false;
if (eapol->conf.wpa)
- sm->portValid = FALSE;
+ sm->portValid = false;
else
- sm->portValid = TRUE;
-
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.eap_server = eapol->conf.eap_server;
- eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
- eap_conf.msg_ctx = eapol->conf.msg_ctx;
- eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
- eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
- eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
- eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
- eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
- eap_conf.eap_teap_auth = eapol->conf.eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = eapol->conf.eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
- eap_conf.eap_sim_id = eapol->conf.eap_sim_id;
- eap_conf.tnc = eapol->conf.tnc;
- eap_conf.wps = eapol->conf.wps;
- eap_conf.assoc_wps_ie = assoc_wps_ie;
- eap_conf.assoc_p2p_ie = assoc_p2p_ie;
- eap_conf.peer_addr = addr;
- eap_conf.fragment_size = eapol->conf.fragment_size;
- eap_conf.pwd_group = eapol->conf.pwd_group;
- eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
- eap_conf.server_id = eapol->conf.server_id;
- eap_conf.server_id_len = eapol->conf.server_id_len;
- eap_conf.erp = eapol->conf.erp;
- eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
- eap_conf.tls_flags = eapol->conf.tls_flags;
- sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+ sm->portValid = true;
+
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ eap_sess.assoc_wps_ie = assoc_wps_ie;
+ eap_sess.assoc_p2p_ie = assoc_p2p_ie;
+ eap_sess.peer_addr = addr;
+ sm->eap = eap_server_sm_init(sm, &eapol_cb, eapol->conf.eap_cfg,
+ &eap_sess);
if (sm->eap == NULL) {
eapol_auth_free(sm);
return NULL;
@@ -934,10 +917,12 @@ restart:
SM_STEP_RUN(BE_AUTH);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(REAUTH_TIMER);
+#ifdef CONFIG_WEP
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(AUTH_KEY_TX);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(KEY_RX);
+#endif /* CONFIG_WEP */
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(CTRL_DIR);
@@ -965,7 +950,7 @@ restart:
/* TODO: find a better location for this */
if (sm->eap_if->aaaEapResp) {
- sm->eap_if->aaaEapResp = FALSE;
+ sm->eap_if->aaaEapResp = false;
if (sm->eap_if->aaaEapRespData == NULL) {
wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
"but no aaaEapRespData available");
@@ -1012,14 +997,14 @@ void eapol_auth_step(struct eapol_state_machine *sm)
static void eapol_auth_initialize(struct eapol_state_machine *sm)
{
- sm->initializing = TRUE;
+ sm->initializing = true;
/* Initialize the state machines by asserting initialize and then
* deasserting it after one step */
- sm->initialize = TRUE;
+ sm->initialize = true;
eapol_sm_step_run(sm);
- sm->initialize = FALSE;
+ sm->initialize = false;
eapol_sm_step_run(sm);
- sm->initializing = FALSE;
+ sm->initializing = false;
/* Start one second tick for port timers state machine */
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
@@ -1107,7 +1092,7 @@ void eapol_auth_reauthenticate(struct eapol_state_machine *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: External reauthentication trigger for "
MACSTR, MAC2STR(sm->addr));
- sm->reAuthenticate = TRUE;
+ sm->reAuthenticate = true;
eapol_auth_step(sm);
}
@@ -1160,9 +1145,9 @@ int eapol_auth_set_conf(struct eapol_state_machine *sm, const char *param,
if (os_strcasecmp(param, "reAuthEnabled") == 0) {
if (os_strcmp(value, "TRUE") == 0)
- sm->reAuthEnabled = TRUE;
+ sm->reAuthEnabled = true;
else if (os_strcmp(value, "FALSE") == 0)
- sm->reAuthEnabled = FALSE;
+ sm->reAuthEnabled = false;
else
return -1;
eapol_auth_step(sm);
@@ -1171,9 +1156,9 @@ int eapol_auth_set_conf(struct eapol_state_machine *sm, const char *param,
if (os_strcasecmp(param, "KeyTransmissionEnabled") == 0) {
if (os_strcmp(value, "TRUE") == 0)
- sm->keyTxEnabled = TRUE;
+ sm->keyTxEnabled = true;
else if (os_strcmp(value, "FALSE") == 0)
- sm->keyTxEnabled = FALSE;
+ sm->keyTxEnabled = false;
else
return -1;
eapol_auth_step(sm);
@@ -1187,19 +1172,14 @@ int eapol_auth_set_conf(struct eapol_state_machine *sm, const char *param,
static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
struct eapol_auth_config *src)
{
+ dst->eap_cfg = src->eap_cfg;
dst->ctx = src->ctx;
dst->eap_reauth_period = src->eap_reauth_period;
dst->wpa = src->wpa;
+#ifdef CONFIG_WEP
dst->individual_wep_key_len = src->individual_wep_key_len;
- dst->eap_server = src->eap_server;
- dst->ssl_ctx = src->ssl_ctx;
- dst->msg_ctx = src->msg_ctx;
- dst->eap_sim_db_priv = src->eap_sim_db_priv;
+#endif /* CONFIG_WEP */
os_free(dst->eap_req_id_text);
- dst->pwd_group = src->pwd_group;
- dst->pbc_in_m1 = src->pbc_in_m1;
- dst->server_id = src->server_id;
- dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
src->eap_req_id_text_len);
@@ -1210,37 +1190,6 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->eap_req_id_text = NULL;
dst->eap_req_id_text_len = 0;
}
- if (src->pac_opaque_encr_key) {
- dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
- 16);
- if (dst->pac_opaque_encr_key == NULL)
- goto fail;
- } else
- dst->pac_opaque_encr_key = NULL;
- if (src->eap_fast_a_id) {
- dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
- src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL)
- goto fail;
- dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
- } else
- dst->eap_fast_a_id = NULL;
- if (src->eap_fast_a_id_info) {
- dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL)
- goto fail;
- } else
- dst->eap_fast_a_id_info = NULL;
- dst->eap_fast_prov = src->eap_fast_prov;
- dst->pac_key_lifetime = src->pac_key_lifetime;
- dst->pac_key_refresh_time = src->pac_key_refresh_time;
- dst->eap_teap_auth = src->eap_teap_auth;
- dst->eap_teap_pac_no_inner = src->eap_teap_pac_no_inner;
- dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
- dst->eap_sim_id = src->eap_sim_id;
- dst->tnc = src->tnc;
- dst->wps = src->wps;
- dst->fragment_size = src->fragment_size;
os_free(dst->erp_domain);
if (src->erp_domain) {
@@ -1251,9 +1200,6 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->erp_domain = NULL;
}
dst->erp_send_reauth_start = src->erp_send_reauth_start;
- dst->erp = src->erp;
- dst->tls_session_lifetime = src->tls_session_lifetime;
- dst->tls_flags = src->tls_flags;
return 0;
@@ -1267,12 +1213,6 @@ static void eapol_auth_conf_free(struct eapol_auth_config *conf)
{
os_free(conf->eap_req_id_text);
conf->eap_req_id_text = NULL;
- os_free(conf->pac_opaque_encr_key);
- conf->pac_opaque_encr_key = NULL;
- os_free(conf->eap_fast_a_id);
- conf->eap_fast_a_id = NULL;
- os_free(conf->eap_fast_a_id_info);
- conf->eap_fast_a_id_info = NULL;
os_free(conf->erp_domain);
conf->erp_domain = NULL;
}
@@ -1292,10 +1232,12 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
return NULL;
}
+#ifdef CONFIG_WEP
if (conf->individual_wep_key_len > 0) {
/* use key0 in individual key and key1 in broadcast key */
eapol->default_wep_key_idx = 1;
}
+#endif /* CONFIG_WEP */
eapol->cb.eapol_send = cb->eapol_send;
eapol->cb.aaa_send = cb->aaa_send;
@@ -1320,6 +1262,8 @@ void eapol_auth_deinit(struct eapol_authenticator *eapol)
return;
eapol_auth_conf_free(&eapol->conf);
+#ifdef CONFIG_WEP
os_free(eapol->default_wep_key);
+#endif /* CONFIG_WEP */
os_free(eapol);
}
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm.h b/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
index bcdd50971569..5fe89c64b3a3 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
@@ -15,38 +15,14 @@
#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
struct eapol_auth_config {
+ const struct eap_config *eap_cfg;
int eap_reauth_period;
int wpa;
int individual_wep_key_len;
- int eap_server;
- void *ssl_ctx;
- void *msg_ctx;
- void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
- int erp; /* Whether ERP is enabled on authentication server */
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- int eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
- int eap_sim_aka_result_ind;
- int eap_sim_id;
- int tnc;
- struct wps_context *wps;
- int fragment_size;
- u16 pwd_group;
- int pbc_in_m1;
- const u8 *server_id;
- size_t server_id_len;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
index 04386b2ce551..3c6898310284 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
@@ -43,23 +43,23 @@ struct eapol_state_machine {
int reAuthWhen;
/* global variables */
- Boolean authAbort;
- Boolean authFail;
+ bool authAbort;
+ bool authFail;
PortState authPortStatus;
- Boolean authStart;
- Boolean authTimeout;
- Boolean authSuccess;
- Boolean eapolEap;
- Boolean initialize;
- Boolean keyDone;
- Boolean keyRun;
- Boolean keyTxEnabled;
+ bool authStart;
+ bool authTimeout;
+ bool authSuccess;
+ bool eapolEap;
+ bool initialize;
+ bool keyDone;
+ bool keyRun;
+ bool keyTxEnabled;
PortTypes portControl;
- Boolean portValid;
- Boolean reAuthenticate;
+ bool portValid;
+ bool reAuthenticate;
/* Port Timers state machine */
- /* 'Boolean tick' implicitly handled as registered timeout */
+ /* 'bool tick' implicitly handled as registered timeout */
/* Authenticator PAE state machine */
enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
@@ -67,8 +67,8 @@ struct eapol_state_machine {
AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
/* variables */
- Boolean eapolLogoff;
- Boolean eapolStart;
+ bool eapolLogoff;
+ bool eapolStart;
PortTypes portMode;
unsigned int reAuthCount;
/* constants */
@@ -109,7 +109,7 @@ struct eapol_state_machine {
} reauth_timer_state;
/* constants */
unsigned int reAuthPeriod; /* default 3600 s */
- Boolean reAuthEnabled;
+ bool reAuthEnabled;
/* Authenticator Key Transmit state machine */
enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
@@ -118,14 +118,14 @@ struct eapol_state_machine {
/* Key Receive state machine */
enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
/* variables */
- Boolean rxKey;
+ bool rxKey;
/* Controlled Directions state machine */
enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
/* variables */
ControlledDirection adminControlledDirections;
ControlledDirection operControlledDirections;
- Boolean operEdge;
+ bool operEdge;
/* Authenticator Statistics Table */
Counter dot1xAuthEapolFramesRx;
@@ -161,8 +161,8 @@ struct eapol_state_machine {
struct eap_sm *eap;
- Boolean initializing; /* in process of initializing state machines */
- Boolean changed;
+ bool initializing; /* in process of initializing state machines */
+ bool changed;
struct eapol_authenticator *eapol;
diff --git a/contrib/wpa/src/eapol_supp/Makefile b/contrib/wpa/src/eapol_supp/Makefile
new file mode 100644
index 000000000000..67a11857bd43
--- /dev/null
+++ b/contrib/wpa/src/eapol_supp/Makefile
@@ -0,0 +1,5 @@
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS = eapol_supp_sm.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/eapol_supp/eapol_supp_sm.c b/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
index f1ca0a859bde..861eea2ae524 100644
--- a/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
+++ b/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
@@ -38,21 +38,21 @@ struct eapol_sm {
int timer_tick_enabled;
/* Global variables */
- Boolean eapFail;
- Boolean eapolEap;
- Boolean eapSuccess;
- Boolean initialize;
- Boolean keyDone;
- Boolean keyRun;
+ bool eapFail;
+ bool eapolEap;
+ bool eapSuccess;
+ bool initialize;
+ bool keyDone;
+ bool keyRun;
PortControl portControl;
- Boolean portEnabled;
+ bool portEnabled;
PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
- Boolean portValid;
- Boolean suppAbort;
- Boolean suppFail;
- Boolean suppStart;
- Boolean suppSuccess;
- Boolean suppTimeout;
+ bool portValid;
+ bool suppAbort;
+ bool suppFail;
+ bool suppStart;
+ bool suppSuccess;
+ bool suppTimeout;
/* Supplicant PAE state machine */
enum {
@@ -69,10 +69,10 @@ struct eapol_sm {
SUPP_PAE_S_FORCE_UNAUTH = 10
} SUPP_PAE_state; /* dot1xSuppPaeState */
/* Variables */
- Boolean userLogoff;
- Boolean logoffSent;
+ bool userLogoff;
+ bool logoffSent;
unsigned int startCount;
- Boolean eapRestart;
+ bool eapRestart;
PortControl sPortMode;
/* Constants */
unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
@@ -85,7 +85,7 @@ struct eapol_sm {
KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
} KEY_RX_state;
/* Variables */
- Boolean rxKey;
+ bool rxKey;
/* Supplicant Backend state machine */
enum {
@@ -100,9 +100,9 @@ struct eapol_sm {
SUPP_BE_SUCCESS = 8
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
/* Variables */
- Boolean eapNoResp;
- Boolean eapReq;
- Boolean eapResp;
+ bool eapNoResp;
+ bool eapReq;
+ bool eapResp;
/* Constants */
unsigned int authPeriod; /* dot1xSuppAuthPeriod */
@@ -120,30 +120,30 @@ struct eapol_sm {
unsigned char dot1xSuppLastEapolFrameSource[6];
/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
- Boolean changed;
+ bool changed;
struct eap_sm *eap;
struct eap_peer_config *config;
- Boolean initial_req;
+ bool initial_req;
u8 *last_rx_key;
size_t last_rx_key_len;
struct wpabuf *eapReqData; /* for EAP */
- Boolean altAccept; /* for EAP */
- Boolean altReject; /* for EAP */
- Boolean eapTriggerStart;
- Boolean replay_counter_valid;
+ bool altAccept; /* for EAP */
+ bool altReject; /* for EAP */
+ bool eapTriggerStart;
+ bool replay_counter_valid;
u8 last_replay_counter[16];
struct eapol_config conf;
struct eapol_ctx *ctx;
enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
cb_status;
- Boolean cached_pmk;
+ bool cached_pmk;
- Boolean unicast_key_received, broadcast_key_received;
+ bool unicast_key_received, broadcast_key_received;
- Boolean force_authorized_update;
+ bool force_authorized_update;
#ifdef CONFIG_EAP_PROXY
- Boolean use_eap_proxy;
+ bool use_eap_proxy;
struct eap_proxy_sm *eap_proxy;
#endif /* CONFIG_EAP_PROXY */
};
@@ -200,6 +200,15 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
}
+static int eapol_sm_confirm_auth(struct eapol_sm *sm)
+{
+ if (!sm->ctx->confirm_auth_cb)
+ return 0;
+
+ return sm->ctx->confirm_auth_cb(sm->ctx->ctx);
+}
+
+
static void eapol_enable_timer_tick(struct eapol_sm *sm)
{
if (sm->timer_tick_enabled)
@@ -215,7 +224,7 @@ SM_STATE(SUPP_PAE, LOGOFF)
{
SM_ENTRY(SUPP_PAE, LOGOFF);
eapol_sm_txLogoff(sm);
- sm->logoffSent = TRUE;
+ sm->logoffSent = true;
eapol_sm_set_port_unauthorized(sm);
}
@@ -225,13 +234,13 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
SM_ENTRY(SUPP_PAE, DISCONNECTED);
sm->sPortMode = Auto;
sm->startCount = 0;
- sm->eapTriggerStart = FALSE;
- sm->logoffSent = FALSE;
+ sm->eapTriggerStart = false;
+ sm->logoffSent = false;
eapol_sm_set_port_unauthorized(sm);
- sm->suppAbort = TRUE;
+ sm->suppAbort = true;
- sm->unicast_key_received = FALSE;
- sm->broadcast_key_received = FALSE;
+ sm->unicast_key_received = false;
+ sm->broadcast_key_received = false;
/*
* IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
@@ -254,7 +263,7 @@ SM_STATE(SUPP_PAE, CONNECTING)
send_start = 1;
if (sm->ctx->preauth)
send_start = 1;
- sm->eapTriggerStart = FALSE;
+ sm->eapTriggerStart = false;
if (send_start) {
sm->startWhen = sm->startPeriod;
@@ -277,7 +286,7 @@ SM_STATE(SUPP_PAE, CONNECTING)
}
}
eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
+ sm->eapolEap = false;
if (send_start)
eapol_sm_txStart(sm);
}
@@ -287,12 +296,12 @@ SM_STATE(SUPP_PAE, AUTHENTICATING)
{
SM_ENTRY(SUPP_PAE, AUTHENTICATING);
sm->startCount = 0;
- sm->suppSuccess = FALSE;
- sm->suppFail = FALSE;
- sm->suppTimeout = FALSE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
- sm->suppStart = TRUE;
+ sm->suppSuccess = false;
+ sm->suppFail = false;
+ sm->suppTimeout = false;
+ sm->keyRun = false;
+ sm->keyDone = false;
+ sm->suppStart = true;
}
@@ -316,17 +325,22 @@ SM_STATE(SUPP_PAE, AUTHENTICATED)
SM_STATE(SUPP_PAE, RESTART)
{
+ if (eapol_sm_confirm_auth(sm)) {
+ /* Don't process restart, we are already reconnecting */
+ return;
+ }
+
SM_ENTRY(SUPP_PAE, RESTART);
- sm->eapRestart = TRUE;
+ sm->eapRestart = true;
if (sm->altAccept) {
/*
* Prevent EAP peer state machine from failing due to prior
- * external EAP success notification (altSuccess=TRUE in the
+ * external EAP success notification (altSuccess=true in the
* IDLE state could result in a transition to the FAILURE state.
*/
wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
- sm->eapSuccess = FALSE;
- sm->altAccept = FALSE;
+ sm->eapSuccess = false;
+ sm->altAccept = false;
}
}
@@ -398,7 +412,7 @@ SM_STEP(SUPP_PAE)
wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
"plaintext connection; no EAPOL-Key frames "
"required");
- sm->portValid = TRUE;
+ sm->portValid = true;
if (sm->ctx->eapol_done_cb)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
@@ -445,7 +459,7 @@ SM_STATE(KEY_RX, KEY_RECEIVE)
{
SM_ENTRY(KEY_RX, KEY_RECEIVE);
eapol_sm_processKey(sm);
- sm->rxKey = FALSE;
+ sm->rxKey = false;
}
@@ -472,7 +486,7 @@ SM_STATE(SUPP_BE, REQUEST)
{
SM_ENTRY(SUPP_BE, REQUEST);
sm->authWhile = 0;
- sm->eapReq = TRUE;
+ sm->eapReq = true;
eapol_sm_getSuppRsp(sm);
}
@@ -481,15 +495,15 @@ SM_STATE(SUPP_BE, RESPONSE)
{
SM_ENTRY(SUPP_BE, RESPONSE);
eapol_sm_txSuppRsp(sm);
- sm->eapResp = FALSE;
+ sm->eapResp = false;
}
SM_STATE(SUPP_BE, SUCCESS)
{
SM_ENTRY(SUPP_BE, SUCCESS);
- sm->keyRun = TRUE;
- sm->suppSuccess = TRUE;
+ sm->keyRun = true;
+ sm->suppSuccess = true;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
@@ -499,7 +513,7 @@ SM_STATE(SUPP_BE, SUCCESS)
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
- sm->replay_counter_valid = FALSE;
+ sm->replay_counter_valid = false;
session_id = eap_proxy_get_eap_session_id(
sm->eap_proxy, &session_id_len);
@@ -520,7 +534,7 @@ SM_STATE(SUPP_BE, SUCCESS)
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
- sm->replay_counter_valid = FALSE;
+ sm->replay_counter_valid = false;
}
}
@@ -528,22 +542,22 @@ SM_STATE(SUPP_BE, SUCCESS)
SM_STATE(SUPP_BE, FAIL)
{
SM_ENTRY(SUPP_BE, FAIL);
- sm->suppFail = TRUE;
+ sm->suppFail = true;
}
SM_STATE(SUPP_BE, TIMEOUT)
{
SM_ENTRY(SUPP_BE, TIMEOUT);
- sm->suppTimeout = TRUE;
+ sm->suppTimeout = true;
}
SM_STATE(SUPP_BE, IDLE)
{
SM_ENTRY(SUPP_BE, IDLE);
- sm->suppStart = FALSE;
- sm->initial_req = TRUE;
+ sm->suppStart = false;
+ sm->initial_req = true;
}
@@ -551,7 +565,7 @@ SM_STATE(SUPP_BE, INITIALIZE)
{
SM_ENTRY(SUPP_BE, INITIALIZE);
eapol_sm_abortSupp(sm);
- sm->suppAbort = FALSE;
+ sm->suppAbort = false;
/*
* IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
@@ -569,9 +583,9 @@ SM_STATE(SUPP_BE, RECEIVE)
SM_ENTRY(SUPP_BE, RECEIVE);
sm->authWhile = sm->authPeriod;
eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
- sm->eapNoResp = FALSE;
- sm->initial_req = FALSE;
+ sm->eapolEap = false;
+ sm->eapNoResp = false;
+ sm->initial_req = false;
}
@@ -678,6 +692,7 @@ struct eap_key_data {
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
@@ -816,7 +831,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
return;
}
- sm->replay_counter_valid = TRUE;
+ sm->replay_counter_valid = true;
os_memcpy(sm->last_replay_counter, key->replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN);
@@ -828,16 +843,16 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
if (sm->ctx->set_wep_key &&
sm->ctx->set_wep_key(sm->ctx->ctx,
- key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+ !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG),
key->key_index & IEEE8021X_KEY_INDEX_MASK,
datakey, key_len) < 0) {
wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
" driver.");
} else {
if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
- sm->unicast_key_received = TRUE;
+ sm->unicast_key_received = true;
else
- sm->broadcast_key_received = TRUE;
+ sm->broadcast_key_received = true;
if ((sm->unicast_key_received ||
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
@@ -846,12 +861,13 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
"frames received");
- sm->portValid = TRUE;
+ sm->portValid = true;
if (sm->ctx->eapol_done_cb)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
}
@@ -933,7 +949,7 @@ static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
int cb;
cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
+ sm->force_authorized_update = false;
sm->suppPortStatus = Authorized;
if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 1);
@@ -945,7 +961,7 @@ static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
int cb;
cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
+ sm->force_authorized_update = false;
sm->suppPortStatus = Unauthorized;
if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 0);
@@ -969,7 +985,7 @@ void eapol_sm_step(struct eapol_sm *sm)
* allow events (e.g., SIGTERM) to stop the program cleanly if the
* state machine were to generate a busy loop. */
for (i = 0; i < 100; i++) {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
@@ -977,11 +993,11 @@ void eapol_sm_step(struct eapol_sm *sm)
if (sm->use_eap_proxy) {
/* Drive the EAP proxy state machine */
if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
- sm->changed = TRUE;
+ sm->changed = true;
} else
#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
- sm->changed = TRUE;
+ sm->changed = true;
if (!sm->changed)
break;
}
@@ -1354,7 +1370,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
if (sm->eapReqData) {
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
eap_proxy_packet_update(
@@ -1395,7 +1411,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
"frame");
os_memcpy(sm->last_rx_key, buf, data_len);
sm->last_rx_key_len = data_len;
- sm->rxKey = TRUE;
+ sm->rxKey = true;
eapol_sm_step(sm);
}
break;
@@ -1438,14 +1454,14 @@ void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
*
* Notify EAPOL state machine about new portEnabled value.
*/
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled)
{
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
"portEnabled=%d", enabled);
if (sm->portEnabled != enabled)
- sm->force_authorized_update = TRUE;
+ sm->force_authorized_update = true;
sm->portEnabled = enabled;
eapol_sm_step(sm);
}
@@ -1458,7 +1474,7 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
*
* Notify EAPOL state machine about new portValid value.
*/
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
+void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid)
{
if (sm == NULL)
return;
@@ -1472,15 +1488,15 @@ void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
/**
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @success: %TRUE = set success, %FALSE = clear success
+ * @success: %true = set success, %false = clear success
*
* Notify the EAPOL state machine that external event has forced EAP state to
- * success (success = %TRUE). This can be cleared by setting success = %FALSE.
+ * success (success = %true). This can be cleared by setting success = %false.
*
* This function is called to update EAP state when WPA-PSK key handshake has
* been completed successfully since WPA-PSK does not use EAP state machine.
*/
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, bool success)
{
if (sm == NULL)
return;
@@ -1497,12 +1513,12 @@ void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
/**
* eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @fail: %TRUE = set failure, %FALSE = clear failure
+ * @fail: %true = set failure, %false = clear failure
*
* Notify EAPOL state machine that external event has forced EAP state to
- * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
+ * failure (fail = %true). This can be cleared by setting fail = %false.
*/
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail)
{
if (sm == NULL)
return;
@@ -1643,7 +1659,7 @@ const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
*
* Notify EAPOL state machines that user requested logon/logoff.
*/
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff)
{
if (sm) {
sm->userLogoff = logoff;
@@ -1668,7 +1684,7 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
- sm->eapSuccess = TRUE;
+ sm->eapSuccess = true;
eap_notify_success(sm->eap);
eapol_sm_step(sm);
}
@@ -1685,7 +1701,7 @@ void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
- sm->cached_pmk = TRUE;
+ sm->cached_pmk = true;
}
@@ -1695,7 +1711,7 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm)
"doing full EAP authentication");
if (sm == NULL)
return;
- sm->cached_pmk = FALSE;
+ sm->cached_pmk = false;
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
eapol_sm_set_port_unauthorized(sm);
@@ -1774,8 +1790,8 @@ void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
"input) notification - retrying pending EAP "
"Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
+ sm->eapolEap = true;
+ sm->eapReq = true;
eapol_sm_step(sm);
}
}
@@ -1844,11 +1860,11 @@ static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
}
-static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
+static bool eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
{
struct eapol_sm *sm = ctx;
if (sm == NULL)
- return FALSE;
+ return false;
switch (variable) {
case EAPOL_eapSuccess:
return sm->eapSuccess;
@@ -1871,12 +1887,12 @@ static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
case EAPOL_eapTriggerStart:
return sm->eapTriggerStart;
}
- return FALSE;
+ return false;
}
static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
- Boolean value)
+ bool value)
{
struct eapol_sm *sm = ctx;
if (sm == NULL)
@@ -1978,8 +1994,8 @@ static void eapol_sm_notify_pending(void *ctx)
if (sm->eapReqData && !sm->eapReq) {
wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
"state machine - retrying pending EAP Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
+ sm->eapolEap = true;
+ sm->eapReq = true;
eapol_sm_step(sm);
}
}
@@ -2125,7 +2141,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
}
#ifdef CONFIG_EAP_PROXY
- sm->use_eap_proxy = FALSE;
+ sm->use_eap_proxy = false;
sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
if (sm->eap_proxy == NULL) {
wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
@@ -2133,10 +2149,10 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
#endif /* CONFIG_EAP_PROXY */
/* Initialize EAPOL state machines */
- sm->force_authorized_update = TRUE;
- sm->initialize = TRUE;
+ sm->force_authorized_update = true;
+ sm->initialize = true;
eapol_sm_step(sm);
- sm->initialize = FALSE;
+ sm->initialize = false;
eapol_sm_step(sm);
if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
diff --git a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
index c9d7522d5f4e..753b947adb7f 100644
--- a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
+++ b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
@@ -298,6 +298,15 @@ struct eapol_ctx {
* @len: Length of anonymous identity in octets
*/
void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+
+ /**
+ * confirm_auth_cb - Callback confirming if we can install a new PTK
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * Returns: 0 when authentication can continue, -1 when reconnecting
+ *
+ * Automatically triggers a reconnect when not.
+ */
+ int (*confirm_auth_cb)(void *ctx);
};
@@ -316,16 +325,16 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
size_t len);
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled);
+void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid);
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, bool success);
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail);
void eapol_sm_notify_config(struct eapol_sm *sm,
struct eap_peer_config *config,
const struct eapol_config *conf);
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len);
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
+void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff);
void eapol_sm_notify_cached(struct eapol_sm *sm);
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm);
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
@@ -388,18 +397,18 @@ static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
{
}
static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm,
- Boolean enabled)
+ bool enabled)
{
}
static inline void eapol_sm_notify_portValid(struct eapol_sm *sm,
- Boolean valid)
+ bool valid)
{
}
static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm,
- Boolean success)
+ bool success)
{
}
-static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail)
{
}
static inline void eapol_sm_notify_config(struct eapol_sm *sm,
@@ -416,7 +425,7 @@ eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
{
return NULL;
}
-static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff)
{
}
static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
diff --git a/contrib/wpa/src/fst/fst.c b/contrib/wpa/src/fst/fst.c
index 32cd941b41e2..21ef3d8b78f7 100644
--- a/contrib/wpa/src/fst/fst.c
+++ b/contrib/wpa/src/fst/fst.c
@@ -20,7 +20,7 @@ struct dl_list fst_global_ctrls_list;
static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
- Boolean connected,
+ bool connected,
const u8 *peer_addr)
{
union fst_event_extra extra;
@@ -42,7 +42,7 @@ struct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
struct fst_group *g;
struct fst_group *group = NULL;
struct fst_iface *iface = NULL;
- Boolean new_group = FALSE;
+ bool new_group = false;
WPA_ASSERT(ifname != NULL);
WPA_ASSERT(iface_obj != NULL);
@@ -62,7 +62,7 @@ struct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
cfg->group_id);
return NULL;
}
- new_group = TRUE;
+ new_group = true;
}
iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
@@ -166,7 +166,7 @@ void fst_global_del_ctrl(struct fst_ctrl_handle *h)
void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
size_t len)
{
- if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
+ if (fst_iface_is_connected(iface, mgmt->sa, false))
fst_session_on_action_rx(iface, mgmt, len);
else
wpa_printf(MSG_DEBUG,
@@ -187,7 +187,7 @@ void fst_notify_peer_connected(struct fst_iface *iface, const u8 *addr)
fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
MAC2STR(addr));
- fst_ctrl_iface_notify_peer_state_change(iface, TRUE, addr);
+ fst_ctrl_iface_notify_peer_state_change(iface, true, addr);
}
@@ -203,17 +203,26 @@ void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr)
fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
MAC2STR(addr));
- fst_ctrl_iface_notify_peer_state_change(iface, FALSE, addr);
+ fst_ctrl_iface_notify_peer_state_change(iface, false, addr);
}
-Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
- struct fst_iface *iface2)
+bool fst_are_ifaces_aggregated(struct fst_iface *iface1,
+ struct fst_iface *iface2)
{
return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
}
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr)
+{
+ fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR,
+ MAC2STR(addr));
+ os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr));
+ fst_group_update_ie(fst_iface_get_group(iface));
+}
+
+
enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
{
switch (mode) {
diff --git a/contrib/wpa/src/fst/fst.h b/contrib/wpa/src/fst/fst.h
index 296749120b2a..2410a6ef1c63 100644
--- a/contrib/wpa/src/fst/fst.h
+++ b/contrib/wpa/src/fst/fst.h
@@ -113,24 +113,24 @@ struct fst_wpa_obj {
* get_peer_first - Get MAC address of the 1st connected STA
* @ctx: User context %ctx
* @get_ctx: Context to be used for %get_peer_next call
- * @mb_only: %TRUE if only multi-band capable peer should be reported
+ * @mb_only: %true if only multi-band capable peer should be reported
* Returns: Address of the 1st connected STA, %NULL if no STAs connected
*/
const u8 * (*get_peer_first)(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only);
+ bool mb_only);
/**
* get_peer_next - Get MAC address of the next connected STA
* @ctx: User context %ctx
* @get_ctx: Context received from %get_peer_first or previous
* %get_peer_next call
- * @mb_only: %TRUE if only multi-band capable peer should be reported
+ * @mb_only: %true if only multi-band capable peer should be reported
* Returns: Address of the next connected STA, %NULL if no more STAs
* connected
*/
const u8 * (*get_peer_next)(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only);
+ bool mb_only);
};
/**
@@ -273,11 +273,18 @@ void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr);
* @iface1: 1st FST interface object
* @iface1: 2nd FST interface object
*
- * Returns: %TRUE if the interfaces belong to the same FST group,
- * %FALSE otherwise
+ * Returns: %true if the interfaces belong to the same FST group,
+ * %false otherwise
*/
-Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
- struct fst_iface *iface2);
+bool fst_are_ifaces_aggregated(struct fst_iface *iface1,
+ struct fst_iface *iface2);
+
+/**
+ * fst_update_mac_addr - Notify FST about MAC address change
+ * @iface: FST interface object
+ * @addr: New MAC address
+ */
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr);
#else /* CONFIG_FST */
diff --git a/contrib/wpa/src/fst/fst_ctrl_aux.h b/contrib/wpa/src/fst/fst_ctrl_aux.h
index 0aff5d061eae..ab80b6fc4b14 100644
--- a/contrib/wpa/src/fst/fst_ctrl_aux.h
+++ b/contrib/wpa/src/fst/fst_ctrl_aux.h
@@ -54,12 +54,12 @@ enum fst_initiator {
union fst_event_extra {
struct fst_event_extra_iface_state {
- Boolean attached;
+ bool attached;
char ifname[FST_MAX_INTERFACE_SIZE];
char group_id[FST_MAX_GROUP_ID_SIZE];
} iface_state; /* for EVENT_FST_IFACE_STATE_CHANGED */
struct fst_event_extra_peer_state {
- Boolean connected;
+ bool connected;
char ifname[FST_MAX_INTERFACE_SIZE];
u8 addr[ETH_ALEN];
} peer_state; /* for EVENT_PEER_STATE_CHANGED */
diff --git a/contrib/wpa/src/fst/fst_ctrl_iface.c b/contrib/wpa/src/fst/fst_ctrl_iface.c
index 7df3362b6e93..45607b6d90d6 100644
--- a/contrib/wpa/src/fst/fst_ctrl_iface.c
+++ b/contrib/wpa/src/fst/fst_ctrl_iface.c
@@ -32,8 +32,8 @@ static struct fst_group * get_fst_group_by_id(const char *id)
/* notifications */
-static Boolean format_session_state_extra(const union fst_event_extra *extra,
- char *buffer, size_t size)
+static bool format_session_state_extra(const union fst_event_extra *extra,
+ char *buffer, size_t size)
{
int len;
char reject_str[32] = FST_CTRL_PVAL_NONE;
@@ -42,7 +42,7 @@ static Boolean format_session_state_extra(const union fst_event_extra *extra,
ss = &extra->session_state;
if (ss->new_state != FST_SESSION_STATE_INITIAL)
- return TRUE;
+ return true;
switch (ss->extra.to_initial.reason) {
case REASON_REJECT:
@@ -183,10 +183,10 @@ static int session_get(const char *session_id, char *buf, size_t buflen)
return os_snprintf(buf, buflen, "FAIL\n");
}
- old_peer_addr = fst_session_get_peer_addr(s, TRUE);
- new_peer_addr = fst_session_get_peer_addr(s, FALSE);
- new_iface = fst_session_get_iface(s, FALSE);
- old_iface = fst_session_get_iface(s, TRUE);
+ old_peer_addr = fst_session_get_peer_addr(s, true);
+ new_peer_addr = fst_session_get_peer_addr(s, false);
+ new_iface = fst_session_get_iface(s, false);
+ old_iface = fst_session_get_iface(s, true);
return os_snprintf(buf, buflen,
FST_CSG_PNAME_OLD_PEER_ADDR "=" MACSTR "\n"
@@ -227,13 +227,13 @@ static int session_set(const char *session_id, char *buf, size_t buflen)
p++;
if (os_strncasecmp(p, FST_CSS_PNAME_OLD_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, TRUE);
+ ret = fst_session_set_str_ifname(s, q + 1, true);
} else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, FALSE);
+ ret = fst_session_set_str_ifname(s, q + 1, false);
} else if (os_strncasecmp(p, FST_CSS_PNAME_OLD_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, TRUE);
+ ret = fst_session_set_str_peer_addr(s, q + 1, true);
} else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, FALSE);
+ ret = fst_session_set_str_peer_addr(s, q + 1, false);
} else if (os_strncasecmp(p, FST_CSS_PNAME_LLT, q - p) == 0) {
ret = fst_session_set_str_llt(s, q + 1);
} else {
@@ -539,8 +539,8 @@ static int iface_peers(const char *group_id, char *buf, size_t buflen)
if (!found)
return os_snprintf(buf, buflen, "FAIL\n");
- addr = fst_iface_get_peer_first(f, &ctx, FALSE);
- for (; addr != NULL; addr = fst_iface_get_peer_next(f, &ctx, FALSE)) {
+ addr = fst_iface_get_peer_first(f, &ctx, false);
+ for (; addr != NULL; addr = fst_iface_get_peer_next(f, &ctx, false)) {
int res;
res = os_snprintf(buf + ret, buflen - ret, MACSTR "\n",
@@ -692,7 +692,7 @@ static int print_band(unsigned num, struct fst_iface *iface, const u8 *addr,
static void fst_ctrl_iface_on_iface_state_changed(struct fst_iface *i,
- Boolean attached)
+ bool attached)
{
union fst_event_extra extra;
@@ -710,14 +710,14 @@ static void fst_ctrl_iface_on_iface_state_changed(struct fst_iface *i,
static int fst_ctrl_iface_on_iface_added(struct fst_iface *i)
{
- fst_ctrl_iface_on_iface_state_changed(i, TRUE);
+ fst_ctrl_iface_on_iface_state_changed(i, true);
return 0;
}
static void fst_ctrl_iface_on_iface_removed(struct fst_iface *i)
{
- fst_ctrl_iface_on_iface_state_changed(i, FALSE);
+ fst_ctrl_iface_on_iface_state_changed(i, false);
}
@@ -749,7 +749,7 @@ int fst_ctrl_iface_mb_info(const u8 *addr, char *buf, size_t buflen)
foreach_fst_group(g) {
foreach_fst_group_iface(g, f) {
- if (fst_iface_is_connected(f, addr, TRUE)) {
+ if (fst_iface_is_connected(f, addr, true)) {
ret += print_band(num++, f, addr,
buf + ret, buflen - ret);
}
@@ -789,7 +789,7 @@ int fst_ctrl_iface_receive(const char *cmd, char *reply, size_t reply_size)
const struct fst_command *c;
const char *p;
const char *temp;
- Boolean non_spaces_found;
+ bool non_spaces_found;
for (c = commands; c->name; c++) {
if (os_strncasecmp(cmd, c->name, os_strlen(c->name)) != 0)
@@ -800,10 +800,10 @@ int fst_ctrl_iface_receive(const char *cmd, char *reply, size_t reply_size)
return os_snprintf(reply, reply_size, "FAIL\n");
p++;
temp = p;
- non_spaces_found = FALSE;
+ non_spaces_found = false;
while (*temp) {
if (!isspace(*temp)) {
- non_spaces_found = TRUE;
+ non_spaces_found = true;
break;
}
temp++;
@@ -818,18 +818,18 @@ int fst_ctrl_iface_receive(const char *cmd, char *reply, size_t reply_size)
}
-int fst_read_next_int_param(const char *params, Boolean *valid, char **endp)
+int fst_read_next_int_param(const char *params, bool *valid, char **endp)
{
int ret = -1;
const char *curp;
- *valid = FALSE;
+ *valid = false;
*endp = (char *) params;
curp = params;
if (*curp) {
ret = (int) strtol(curp, endp, 0);
if (!**endp || isspace(**endp))
- *valid = TRUE;
+ *valid = true;
}
return ret;
@@ -887,7 +887,7 @@ int fst_parse_attach_command(const char *cmd, char *ifname, size_t ifname_size,
{
char *pos;
char *endp;
- Boolean is_valid;
+ bool is_valid;
int val;
if (fst_read_next_text_param(cmd, ifname, ifname_size, &endp) ||
diff --git a/contrib/wpa/src/fst/fst_ctrl_iface.h b/contrib/wpa/src/fst/fst_ctrl_iface.h
index 4d0cd9fce4e0..354b81fc77ec 100644
--- a/contrib/wpa/src/fst/fst_ctrl_iface.h
+++ b/contrib/wpa/src/fst/fst_ctrl_iface.h
@@ -30,7 +30,7 @@ fst_ctrl_iface_mb_info(const u8 *addr, char *buf, size_t buflen)
#endif /* CONFIG_FST */
-int fst_read_next_int_param(const char *params, Boolean *valid, char **endp);
+int fst_read_next_int_param(const char *params, bool *valid, char **endp);
int fst_read_next_text_param(const char *params, char *buf, size_t buflen,
char **endp);
int fst_read_peer_addr(const char *mac, u8 *peer_addr);
diff --git a/contrib/wpa/src/fst/fst_group.c b/contrib/wpa/src/fst/fst_group.c
index a4ae016d9163..d1c4014971b3 100644
--- a/contrib/wpa/src/fst/fst_group.c
+++ b/contrib/wpa/src/fst/fst_group.c
@@ -305,7 +305,7 @@ fst_group_get_peer_other_connection_1(struct fst_iface *iface,
if (other_iface == iface ||
band_id != fst_iface_get_band_id(other_iface))
continue;
- if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+ if (fst_iface_is_connected(other_iface, tmp_peer_addr, false)) {
os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
return other_iface;
}
@@ -347,10 +347,10 @@ fst_group_get_peer_other_connection_2(struct fst_iface *iface,
band_id != fst_iface_get_band_id(other_iface))
continue;
cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
- TRUE);
+ true);
for (; cur_peer_addr;
cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
- TRUE)) {
+ true)) {
cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
cur_peer_addr);
if (!cur_mbie)
@@ -493,9 +493,9 @@ void fst_group_delete(struct fst_group *group)
}
-Boolean fst_group_delete_if_empty(struct fst_group *group)
+bool fst_group_delete_if_empty(struct fst_group *group)
{
- Boolean is_empty = !fst_group_has_ifaces(group) &&
+ bool is_empty = !fst_group_has_ifaces(group) &&
!fst_session_global_get_first_by_group(group);
if (is_empty)
diff --git a/contrib/wpa/src/fst/fst_group.h b/contrib/wpa/src/fst/fst_group.h
index 00aee9c8c25c..4a9ff3e820e1 100644
--- a/contrib/wpa/src/fst/fst_group.h
+++ b/contrib/wpa/src/fst/fst_group.h
@@ -29,7 +29,7 @@ void fst_group_delete(struct fst_group *g);
void fst_group_update_ie(struct fst_group *g);
-static inline Boolean fst_group_has_ifaces(struct fst_group *g)
+static inline bool fst_group_has_ifaces(struct fst_group *g)
{
return !dl_list_empty(&g->ifaces);
}
@@ -44,7 +44,7 @@ static inline const char * fst_group_get_id(struct fst_group *g)
return g->group_id;
}
-Boolean fst_group_delete_if_empty(struct fst_group *group);
+bool fst_group_delete_if_empty(struct fst_group *group);
struct fst_iface * fst_group_get_iface_by_name(struct fst_group *g,
const char *ifname);
struct fst_iface *
diff --git a/contrib/wpa/src/fst/fst_iface.c b/contrib/wpa/src/fst/fst_iface.c
index 35e83cb7b471..90c5fc0357ed 100644
--- a/contrib/wpa/src/fst/fst_iface.c
+++ b/contrib/wpa/src/fst/fst_iface.c
@@ -49,17 +49,17 @@ void fst_iface_delete(struct fst_iface *i)
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
- Boolean mb_only)
+bool fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ bool mb_only)
{
struct fst_get_peer_ctx *ctx;
const u8 *a = fst_iface_get_peer_first(iface, &ctx, mb_only);
for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, mb_only))
if (os_memcmp(addr, a, ETH_ALEN) == 0)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
diff --git a/contrib/wpa/src/fst/fst_iface.h b/contrib/wpa/src/fst/fst_iface.h
index cbaa7d81788d..af7156cb2cb0 100644
--- a/contrib/wpa/src/fst/fst_iface.h
+++ b/contrib/wpa/src/fst/fst_iface.h
@@ -111,20 +111,20 @@ static inline void fst_iface_update_mb_ie(struct fst_iface *i,
static inline const u8 * fst_iface_get_peer_first(struct fst_iface *i,
struct fst_get_peer_ctx **ctx,
- Boolean mb_only)
+ bool mb_only)
{
return i->iface_obj.get_peer_first(i->iface_obj.ctx, ctx, mb_only);
}
static inline const u8 * fst_iface_get_peer_next(struct fst_iface *i,
struct fst_get_peer_ctx **ctx,
- Boolean mb_only)
+ bool mb_only)
{
return i->iface_obj.get_peer_next(i->iface_obj.ctx, ctx, mb_only);
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
- Boolean mb_only);
+bool fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ bool mb_only);
void fst_iface_attach_mbie(struct fst_iface *i, struct wpabuf *mbie);
enum mb_band_id fst_iface_get_band_id(struct fst_iface *i);
diff --git a/contrib/wpa/src/fst/fst_session.c b/contrib/wpa/src/fst/fst_session.c
index a02a93e76e43..e42a85c0403a 100644
--- a/contrib/wpa/src/fst/fst_session.c
+++ b/contrib/wpa/src/fst/fst_session.c
@@ -71,7 +71,7 @@ struct fst_session {
* specific session object */
struct fst_group *group;
enum fst_session_state state;
- Boolean stt_armed;
+ bool stt_armed;
};
static struct dl_list global_sessions_list;
@@ -145,12 +145,12 @@ static u32 fst_find_free_session_id(void)
struct fst_session *s;
for (i = 0; i < (u32) -1; i++) {
- Boolean in_use = FALSE;
+ bool in_use = false;
foreach_fst_session(s) {
if (s->id == global_session_id) {
fst_session_global_inc_id();
- in_use = TRUE;
+ in_use = true;
break;
}
}
@@ -184,7 +184,7 @@ static void fst_session_stt_arm(struct fst_session *s)
/* Action frames sometimes get delayed. Use relaxed timeout (2*) */
eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
fst_session_timeout_handler, NULL, s);
- s->stt_armed = TRUE;
+ s->stt_armed = true;
}
@@ -192,12 +192,12 @@ static void fst_session_stt_disarm(struct fst_session *s)
{
if (s->stt_armed) {
eloop_cancel_timeout(fst_session_timeout_handler, NULL, s);
- s->stt_armed = FALSE;
+ s->stt_armed = false;
}
}
-static Boolean fst_session_is_in_transition(struct fst_session *s)
+static bool fst_session_is_in_transition(struct fst_session *s)
{
/* See spec, 10.32.2.2 Transitioning between states */
return s->stt_armed;
@@ -267,7 +267,7 @@ static void fst_session_reset_ex(struct fst_session *s, enum fst_reason reason)
}
-static int fst_session_send_action(struct fst_session *s, Boolean old_iface,
+static int fst_session_send_action(struct fst_session *s, bool old_iface,
const void *payload, size_t size,
const struct wpabuf *extra_buf)
{
@@ -344,11 +344,11 @@ static int fst_session_send_tear_down(struct fst_session *s)
td.action = FST_ACTION_TEAR_DOWN;
td.fsts_id = host_to_le32(s->data.fsts_id);
- res = fst_session_send_action(s, TRUE, &td, sizeof(td), NULL);
+ res = fst_session_send_action(s, true, &td, sizeof(td), NULL);
if (!res)
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST TearDown sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST TearDown sent");
else
- fst_printf_sframe(s, TRUE, MSG_ERROR,
+ fst_printf_sframe(s, true, MSG_ERROR,
"failed to send FST TearDown");
return res;
@@ -481,10 +481,10 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
return;
}
- fst_session_set_iface(s, iface, TRUE);
- fst_session_set_peer_addr(s, mgmt->sa, TRUE);
- fst_session_set_iface(s, new_iface, FALSE);
- fst_session_set_peer_addr(s, new_iface_peer_addr, FALSE);
+ fst_session_set_iface(s, iface, true);
+ fst_session_set_peer_addr(s, mgmt->sa, true);
+ fst_session_set_iface(s, new_iface, false);
+ fst_session_set_peer_addr(s, new_iface_peer_addr, false);
fst_session_set_llt(s, FST_LLT_VAL_TO_MS(le_to_host32(req->llt)));
s->data.pending_setup_req_dlgt = req->dialog_token;
s->data.fsts_id = le_to_host32(req->stie.fsts_id);
@@ -687,8 +687,8 @@ static void fst_session_handle_ack_request(struct fst_session *s,
res.dialog_token = req->dialog_token;
res.fsts_id = req->fsts_id;
- if (!fst_session_send_action(s, FALSE, &res, sizeof(res), NULL)) {
- fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Response sent");
+ if (!fst_session_send_action(s, false, &res, sizeof(res), NULL)) {
+ fst_printf_sframe(s, false, MSG_INFO, "FST Ack Response sent");
fst_session_stt_disarm(s);
fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
NULL);
@@ -785,7 +785,7 @@ struct fst_session * fst_session_create(struct fst_group *g)
void fst_session_set_iface(struct fst_session *s, struct fst_iface *iface,
- Boolean is_old)
+ bool is_old)
{
if (is_old)
s->data.old_iface = iface;
@@ -802,7 +802,7 @@ void fst_session_set_llt(struct fst_session *s, u32 llt)
void fst_session_set_peer_addr(struct fst_session *s, const u8 *addr,
- Boolean is_old)
+ bool is_old)
{
u8 *a = is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
@@ -850,14 +850,14 @@ int fst_session_initiate_setup(struct fst_session *s)
}
if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
- FALSE)) {
+ false)) {
fst_printf_session(s, MSG_ERROR,
"The preset old peer address is not connected");
return -EINVAL;
}
if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
- FALSE)) {
+ false)) {
fst_printf_session(s, MSG_ERROR,
"The preset new peer address is not connected");
return -EINVAL;
@@ -905,12 +905,12 @@ int fst_session_initiate_setup(struct fst_session *s)
req.stie.old_band_op = 1;
req.stie.old_band_setup = 0;
- res = fst_session_send_action(s, TRUE, &req, sizeof(req),
+ res = fst_session_send_action(s, true, &req, sizeof(req),
fst_iface_get_mbie(s->data.old_iface));
if (!res) {
s->data.fsts_id = fsts_id;
s->data.pending_setup_req_dlgt = dialog_token;
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Request sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST Setup Request sent");
fst_session_set_state(s, FST_SESSION_STATE_SETUP_COMPLETION,
NULL);
@@ -955,7 +955,7 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
}
if (!fst_iface_is_connected(s->data.old_iface,
- s->data.old_peer_addr, FALSE)) {
+ s->data.old_peer_addr, false)) {
fst_printf_session(s, MSG_ERROR,
"The preset peer address is not in the peer list");
return -EINVAL;
@@ -1000,15 +1000,15 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
status_code);
}
- if (fst_session_send_action(s, TRUE, &res, sizeof(res),
+ if (fst_session_send_action(s, true, &res, sizeof(res),
fst_iface_get_mbie(s->data.old_iface))) {
- fst_printf_sframe(s, TRUE, MSG_ERROR,
+ fst_printf_sframe(s, true, MSG_ERROR,
"cannot send FST Setup Response with code %d",
status_code);
return -EINVAL;
}
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Response sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST Setup Response sent");
if (status_code != WLAN_STATUS_SUCCESS) {
union fst_session_state_switch_extra evext = {
@@ -1053,14 +1053,14 @@ int fst_session_initiate_switch(struct fst_session *s)
req.dialog_token = dialog_token;
req.fsts_id = host_to_le32(s->data.fsts_id);
- res = fst_session_send_action(s, FALSE, &req, sizeof(req), NULL);
+ res = fst_session_send_action(s, false, &req, sizeof(req), NULL);
if (!res) {
- fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Request sent");
+ fst_printf_sframe(s, false, MSG_INFO, "FST Ack Request sent");
fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
NULL);
fst_session_stt_arm(s);
} else {
- fst_printf_sframe(s, FALSE, MSG_ERROR,
+ fst_printf_sframe(s, false, MSG_ERROR,
"Cannot send FST Ack Request");
}
@@ -1091,7 +1091,7 @@ void fst_session_handle_action(struct fst_session *s,
break;
case FST_ACTION_ON_CHANNEL_TUNNEL:
default:
- fst_printf_sframe(s, FALSE, MSG_ERROR,
+ fst_printf_sframe(s, false, MSG_ERROR,
"Unsupported FST Action frame");
break;
}
@@ -1137,7 +1137,7 @@ struct fst_group * fst_session_get_group(struct fst_session *s)
}
-struct fst_iface * fst_session_get_iface(struct fst_session *s, Boolean is_old)
+struct fst_iface * fst_session_get_iface(struct fst_session *s, bool is_old)
{
return is_old ? s->data.old_iface : s->data.new_iface;
}
@@ -1149,7 +1149,7 @@ u32 fst_session_get_id(struct fst_session *s)
}
-const u8 * fst_session_get_peer_addr(struct fst_session *s, Boolean is_old)
+const u8 * fst_session_get_peer_addr(struct fst_session *s, bool is_old)
{
return is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
}
@@ -1232,7 +1232,7 @@ void fst_session_on_action_rx(struct fst_iface *iface,
int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
- Boolean is_old)
+ bool is_old)
{
struct fst_group *g = fst_session_get_group(s);
struct fst_iface *i;
@@ -1252,7 +1252,7 @@ int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
- Boolean is_old)
+ bool is_old)
{
u8 peer_addr[ETH_ALEN];
int res = fst_read_peer_addr(mac, peer_addr);
@@ -1330,11 +1330,11 @@ static int get_group_fill_session(struct fst_group **g, struct fst_session *s)
if (!s->data.old_iface)
return -EINVAL;
- old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, TRUE);
+ old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, true);
if (!old_addr)
return -EINVAL;
- new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, TRUE);
+ new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, true);
if (!new_addr)
return -EINVAL;
@@ -1350,7 +1350,7 @@ static int get_group_fill_session(struct fst_group **g, struct fst_session *s)
int fst_test_req_send_fst_request(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_setup_req req;
struct fst_session s;
@@ -1394,7 +1394,7 @@ int fst_test_req_send_fst_request(const char *params)
req.stie.new_band_id = req.stie.old_band_id;
}
- return fst_session_send_action(&s, TRUE, &req, sizeof(req),
+ return fst_session_send_action(&s, true, &req, sizeof(req),
s.data.old_iface->mb_ie);
}
@@ -1402,7 +1402,7 @@ int fst_test_req_send_fst_request(const char *params)
int fst_test_req_send_fst_response(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_setup_res res;
struct fst_session s;
@@ -1437,7 +1437,7 @@ int fst_test_req_send_fst_response(const char *params)
* If some session has just received an FST Setup Request, then
* use the correct dialog token copied from this request.
*/
- _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, TRUE),
+ _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, true),
g);
res.dialog_token = (_s && fst_session_is_ready_pending(_s)) ?
_s->data.pending_setup_req_dlgt : g->dialog_token;
@@ -1469,7 +1469,7 @@ int fst_test_req_send_fst_response(const char *params)
res.stie.new_band_id = res.stie.old_band_id;
}
- return fst_session_send_action(&s, TRUE, &res, sizeof(res),
+ return fst_session_send_action(&s, true, &res, sizeof(res),
s.data.old_iface->mb_ie);
}
@@ -1477,7 +1477,7 @@ int fst_test_req_send_fst_response(const char *params)
int fst_test_req_send_ack_request(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_ack_req req;
struct fst_session s;
@@ -1498,14 +1498,14 @@ int fst_test_req_send_ack_request(const char *params)
req.dialog_token = g->dialog_token;
req.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
+ return fst_session_send_action(&s, false, &req, sizeof(req), NULL);
}
int fst_test_req_send_ack_response(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_ack_res res;
struct fst_session s;
@@ -1526,14 +1526,14 @@ int fst_test_req_send_ack_response(const char *params)
res.dialog_token = g->dialog_token;
res.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
+ return fst_session_send_action(&s, false, &res, sizeof(res), NULL);
}
int fst_test_req_send_tear_down(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_tear_down td;
struct fst_session s;
@@ -1553,14 +1553,14 @@ int fst_test_req_send_tear_down(const char *params)
td.action = FST_ACTION_TEAR_DOWN;
td.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
+ return fst_session_send_action(&s, true, &td, sizeof(td), NULL);
}
u32 fst_test_req_get_fsts_id(const char *params)
{
int sid;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_session *s;
diff --git a/contrib/wpa/src/fst/fst_session.h b/contrib/wpa/src/fst/fst_session.h
index 1162de4b367a..e43d0ea39e18 100644
--- a/contrib/wpa/src/fst/fst_session.h
+++ b/contrib/wpa/src/fst/fst_session.h
@@ -24,10 +24,10 @@ fst_session_global_get_first_by_group(struct fst_group *g);
struct fst_session * fst_session_create(struct fst_group *g);
void fst_session_set_iface(struct fst_session *s, struct fst_iface *iface,
- Boolean is_old);
+ bool is_old);
void fst_session_set_llt(struct fst_session *s, u32 llt);
void fst_session_set_peer_addr(struct fst_session *s, const u8 *addr,
- Boolean is_old);
+ bool is_old);
int fst_session_initiate_setup(struct fst_session *s);
int fst_session_respond(struct fst_session *s, u8 status_code);
int fst_session_initiate_switch(struct fst_session *s);
@@ -39,8 +39,8 @@ void fst_session_reset(struct fst_session *s);
void fst_session_delete(struct fst_session *s);
struct fst_group * fst_session_get_group(struct fst_session *s);
-struct fst_iface * fst_session_get_iface(struct fst_session *s, Boolean is_old);
-const u8 * fst_session_get_peer_addr(struct fst_session *s, Boolean is_old);
+struct fst_iface * fst_session_get_iface(struct fst_session *s, bool is_old);
+const u8 * fst_session_get_peer_addr(struct fst_session *s, bool is_old);
u32 fst_session_get_id(struct fst_session *s);
u32 fst_session_get_llt(struct fst_session *s);
enum fst_session_state fst_session_get_state(struct fst_session *s);
@@ -57,9 +57,9 @@ void fst_session_on_action_rx(struct fst_iface *iface,
int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
- Boolean is_old);
+ bool is_old);
int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
- Boolean is_old);
+ bool is_old);
int fst_session_set_str_llt(struct fst_session *s, const char *llt_str);
#ifdef CONFIG_FST_TEST
diff --git a/contrib/wpa/src/l2_packet/Makefile b/contrib/wpa/src/l2_packet/Makefile
new file mode 100644
index 000000000000..c616626bd3c7
--- /dev/null
+++ b/contrib/wpa/src/l2_packet/Makefile
@@ -0,0 +1,3 @@
+LIB_OBJS = l2_packet_linux.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/l2_packet/l2_packet.h b/contrib/wpa/src/l2_packet/l2_packet.h
index 53871774b4e7..6a862806fc00 100644
--- a/contrib/wpa/src/l2_packet/l2_packet.h
+++ b/contrib/wpa/src/l2_packet/l2_packet.h
@@ -61,6 +61,10 @@ enum l2_packet_filter_type {
* points to len bytes of the payload after the layer 2 header and similarly,
* TX buffers start with payload. This behavior can be changed by setting
* l2_hdr=1 to include the layer 2 header in the data buffer.
+ *
+ * IF rx_callback is NULL, receive operation is not opened at all, i.e., only
+ * the TX path and additional helper functions for fetching MAC and IP
+ * addresses can be used.
*/
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
diff --git a/contrib/wpa/src/l2_packet/l2_packet_freebsd.c b/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
index aa836482767b..48e18fffba57 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
@@ -8,7 +8,8 @@
*/
#include "includes.h"
-#if defined(__APPLE__) || defined(__GLIBC__)
+#include <sys/param.h>
+#if defined(__APPLE__) || defined(__GLIBC__) || defined(__FreeBSD_version)
#include <net/bpf.h>
#endif /* __APPLE__ */
#include <pcap.h>
@@ -84,7 +85,7 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
packet = pcap_next(pcap, &hdr);
- if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ if (!l2->rx_callback || !packet || hdr.caplen < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) packet;
diff --git a/contrib/wpa/src/l2_packet/l2_packet_linux.c b/contrib/wpa/src/l2_packet/l2_packet_linux.c
new file mode 100644
index 000000000000..7897bc026a1b
--- /dev/null
+++ b/contrib/wpa/src/l2_packet/l2_packet_linux.c
@@ -0,0 +1,515 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Linux packet sockets
+ * 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 <sys/ioctl.h>
+#include <netpacket/packet.h>
+#include <net/if.h>
+#include <linux/filter.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/crypto.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+ int fd; /* packet socket for EAPOL frames */
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+ * buffers */
+
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ /* For working around Linux packet socket behavior and regression. */
+ int fd_br_rx;
+ int last_from_br, last_from_br_prev;
+ u8 last_hash[SHA1_MAC_LEN];
+ u8 last_hash_prev[SHA1_MAC_LEN];
+ unsigned int num_rx_br;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+};
+
+/* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
+ * src port bootps and dst port bootpc'
+ */
+static struct sock_filter dhcp_sock_filter_insns[] = {
+ { 0x80, 0, 0, 0x00000000 },
+ { 0x35, 0, 12, 0x00000116 },
+ { 0x28, 0, 0, 0x0000000c },
+ { 0x15, 0, 10, 0x00000800 },
+ { 0x30, 0, 0, 0x00000017 },
+ { 0x15, 0, 8, 0x00000011 },
+ { 0x28, 0, 0, 0x00000014 },
+ { 0x45, 6, 0, 0x00001fff },
+ { 0xb1, 0, 0, 0x0000000e },
+ { 0x48, 0, 0, 0x0000000e },
+ { 0x15, 0, 3, 0x00000043 },
+ { 0x48, 0, 0, 0x00000010 },
+ { 0x15, 0, 1, 0x00000044 },
+ { 0x6, 0, 0, 0x00000bb8 },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog dhcp_sock_filter = {
+ .len = ARRAY_SIZE(dhcp_sock_filter_insns),
+ .filter = dhcp_sock_filter_insns,
+};
+
+
+/* Generated by 'sudo tcpdump -dd -s 1500 multicast and ip6[6]=58' */
+static struct sock_filter ndisc_sock_filter_insns[] = {
+ { 0x30, 0, 0, 0x00000000 },
+ { 0x45, 0, 5, 0x00000001 },
+ { 0x28, 0, 0, 0x0000000c },
+ { 0x15, 0, 3, 0x000086dd },
+ { 0x30, 0, 0, 0x00000014 },
+ { 0x15, 0, 1, 0x0000003a },
+ { 0x6, 0, 0, 0x000005dc },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog ndisc_sock_filter = {
+ .len = ARRAY_SIZE(ndisc_sock_filter_insns),
+ .filter = ndisc_sock_filter_insns,
+};
+
+/* drop packet if skb->pkt_type is PACKET_OTHERHOST (0x03). Generated by:
+ * $ bpfc - <<EOF
+ * > ldb #type
+ * > jeq #0x03, drop
+ * > pass: ret #-1
+ * > drop: ret #0
+ * > EOF
+ */
+static struct sock_filter pkt_type_filter_insns[] = {
+ { 0x30, 0, 0, 0xfffff004 },
+ { 0x15, 1, 0, 0x00000003 },
+ { 0x6, 0, 0, 0xffffffff },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog pkt_type_sock_filter = {
+ .len = ARRAY_SIZE(pkt_type_filter_insns),
+ .filter = pkt_type_filter_insns,
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+ if (l2 == NULL)
+ return -1;
+ if (l2->l2_hdr) {
+ ret = send(l2->fd, buf, len, 0);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
+ strerror(errno));
+ } else {
+ struct sockaddr_ll ll;
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = l2->ifindex;
+ ll.sll_protocol = htons(proto);
+ ll.sll_halen = ETH_ALEN;
+ os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
+ ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
+ sizeof(ll));
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
+ strerror(errno));
+ }
+ }
+ return ret;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ u8 buf[2300];
+ int res;
+ struct sockaddr_ll ll;
+ socklen_t fromlen;
+
+ os_memset(&ll, 0, sizeof(ll));
+ fromlen = sizeof(ll);
+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
+ &fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s",
+ strerror(errno));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
+ __func__, MAC2STR(ll.sll_addr), (int) res);
+
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ if (l2->fd_br_rx >= 0) {
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+ const struct l2_ethhdr *eth = (const struct l2_ethhdr *) buf;
+
+ /*
+ * Close the workaround socket if the kernel version seems to be
+ * able to deliver packets through the packet socket before
+ * authorization has been completed (in dormant state).
+ */
+ if (l2->num_rx_br <= 1 &&
+ (os_memcmp(eth->h_dest, l2->own_addr, ETH_ALEN) == 0 ||
+ is_multicast_ether_addr(eth->h_dest))) {
+ wpa_printf(MSG_DEBUG,
+ "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket",
+ l2->ifname);
+ eloop_unregister_read_sock(l2->fd_br_rx);
+ close(l2->fd_br_rx);
+ l2->fd_br_rx = -1;
+ }
+
+ addr[0] = buf;
+ len[0] = res;
+ sha1_vector(1, addr, len, hash);
+ if (l2->last_from_br &&
+ os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX",
+ __func__);
+ return;
+ }
+ if (l2->last_from_br_prev &&
+ os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)",
+ __func__);
+ return;
+ }
+ os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN);
+ l2->last_from_br_prev = l2->last_from_br;
+ os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
+ }
+
+ l2->last_from_br = 0;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+ l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
+}
+
+
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ u8 buf[2300];
+ int res;
+ struct sockaddr_ll ll;
+ socklen_t fromlen;
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+
+ l2->num_rx_br++;
+ os_memset(&ll, 0, sizeof(ll));
+ fromlen = sizeof(ll);
+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
+ &fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "l2_packet_receive_br - recvfrom: %s",
+ strerror(errno));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d",
+ __func__, MAC2STR(ll.sll_addr), (int) res);
+
+ if (os_memcmp(ll.sll_addr, l2->own_addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Drop RX of own frame", __func__);
+ return;
+ }
+
+ addr[0] = buf;
+ len[0] = res;
+ sha1_vector(1, addr, len, hash);
+ if (!l2->last_from_br &&
+ os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__);
+ return;
+ }
+ if (!l2->last_from_br_prev &&
+ os_memcmp(hash, l2->last_hash_prev, SHA1_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX(prev)", __func__);
+ return;
+ }
+ os_memcpy(l2->last_hash_prev, l2->last_hash, SHA1_MAC_LEN);
+ l2->last_from_br_prev = l2->last_from_br;
+ l2->last_from_br = 1;
+ os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN);
+ l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
+}
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+ struct ifreq ifr;
+ struct sockaddr_ll ll;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ l2->fd_br_rx = -1;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+
+ l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
+ htons(protocol));
+ if (l2->fd < 0) {
+ wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s",
+ __func__, strerror(errno));
+ os_free(l2);
+ return NULL;
+ }
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s",
+ __func__, strerror(errno));
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+ l2->ifindex = ifr.ifr_ifindex;
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = PF_PACKET;
+ ll.sll_ifindex = ifr.ifr_ifindex;
+ ll.sll_protocol = htons(protocol);
+ if (rx_callback &&
+ bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
+ __func__, strerror(errno));
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+
+ if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s",
+ __func__, strerror(errno));
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+ os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ if (rx_callback)
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+ return l2;
+}
+
+
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ struct sock_filter ethertype_sock_filter_insns[] = {
+ /* Load ethertype */
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 2 * ETH_ALEN),
+ /* Jump over next statement if ethertype does not match */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, protocol, 0, 1),
+ /* Ethertype match - return all */
+ BPF_STMT(BPF_RET | BPF_K, ~0),
+ /* No match - drop */
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ const struct sock_fprog ethertype_sock_filter = {
+ .len = ARRAY_SIZE(ethertype_sock_filter_insns),
+ .filter = ethertype_sock_filter_insns,
+ };
+ struct sockaddr_ll ll;
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+
+ l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+ if (!l2)
+ return NULL;
+
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ /*
+ * The Linux packet socket behavior has changed over the years and there
+ * is an inconvenient regression in it that breaks RX for a specific
+ * protocol from interfaces in a bridge when that interface is not in
+ * fully operation state (i.e., when in station mode and not completed
+ * authorization). To work around this, register ETH_P_ALL version of
+ * the packet socket bound to the real netdev and use socket filter to
+ * match the ethertype value. This version is less efficient, but
+ * required for functionality with many kernel version. If the main
+ * packet socket is found to be working, this less efficient version
+ * gets closed automatically.
+ */
+
+ l2->fd_br_rx = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
+ htons(ETH_P_ALL));
+ if (l2->fd_br_rx < 0) {
+ wpa_printf(MSG_DEBUG, "%s: socket(PF_PACKET-fd_br_rx): %s",
+ __func__, strerror(errno));
+ /* try to continue without the workaround RX socket */
+ return l2;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = PF_PACKET;
+ ll.sll_ifindex = if_nametoindex(ifname);
+ ll.sll_protocol = htons(ETH_P_ALL);
+ if (bind(l2->fd_br_rx, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: bind[PF_PACKET-fd_br_rx]: %s",
+ __func__, strerror(errno));
+ /* try to continue without the workaround RX socket */
+ close(l2->fd_br_rx);
+ l2->fd_br_rx = -1;
+ return l2;
+ }
+
+ if (setsockopt(l2->fd_br_rx, SOL_SOCKET, SO_ATTACH_FILTER,
+ &ethertype_sock_filter, sizeof(struct sock_fprog))) {
+ wpa_printf(MSG_DEBUG,
+ "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ /* try to continue without the workaround RX socket */
+ close(l2->fd_br_rx);
+ l2->fd_br_rx = -1;
+ return l2;
+ }
+
+ eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL);
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ if (l2->fd >= 0) {
+ eloop_unregister_read_sock(l2->fd);
+ close(l2->fd);
+ }
+
+#ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ if (l2->fd_br_rx >= 0) {
+ eloop_unregister_read_sock(l2->fd_br_rx);
+ close(l2->fd_br_rx);
+ }
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
+
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ int s;
+ struct ifreq ifr;
+ struct sockaddr_in *saddr;
+ size_t res;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "%s: socket: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ if (errno != EADDRNOTAVAIL)
+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s",
+ __func__, strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
+ if (saddr->sin_family != AF_INET)
+ return -1;
+ res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
+ if (res >= len)
+ return -1;
+ return 0;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ const struct sock_fprog *sock_filter;
+
+ if (TEST_FAIL())
+ return -1;
+
+ switch (type) {
+ case L2_PACKET_FILTER_DHCP:
+ sock_filter = &dhcp_sock_filter;
+ break;
+ case L2_PACKET_FILTER_NDISC:
+ sock_filter = &ndisc_sock_filter;
+ break;
+ case L2_PACKET_FILTER_PKTTYPE:
+ sock_filter = &pkt_type_sock_filter;
+ break;
+ default:
+ return -1;
+ }
+
+ if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER,
+ sock_filter, sizeof(struct sock_fprog))) {
+ wpa_printf(MSG_ERROR,
+ "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_ndis.c b/contrib/wpa/src/l2_packet/l2_packet_ndis.c
index 716778164af4..4a4b639fd220 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_ndis.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_ndis.c
@@ -294,7 +294,8 @@ static void l2_packet_callback(struct l2_packet_data *l2)
}
rx_src = ethhdr->h_source;
- l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
+ if (l2->rx_callback)
+ l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
#ifndef _WIN32_WCE
l2_ndisuio_start_read(l2, 1);
#endif /* _WIN32_WCE */
diff --git a/contrib/wpa/src/l2_packet/l2_packet_none.c b/contrib/wpa/src/l2_packet/l2_packet_none.c
index 307fc6daa403..bc7a4e82d672 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_none.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_none.c
@@ -84,7 +84,7 @@ struct l2_packet_data * l2_packet_init(
* TODO: open connection for receiving frames
*/
l2->fd = -1;
- if (l2->fd >= 0)
+ if (rx_callback && l2->fd >= 0)
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
@@ -112,7 +112,7 @@ void l2_packet_deinit(struct l2_packet_data *l2)
eloop_unregister_read_sock(l2->fd);
/* TODO: close connection */
}
-
+
os_free(l2);
}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_pcap.c b/contrib/wpa/src/l2_packet/l2_packet_pcap.c
new file mode 100644
index 000000000000..c2b17fcf809c
--- /dev/null
+++ b/contrib/wpa/src/l2_packet/l2_packet_pcap.c
@@ -0,0 +1,400 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
+ * Copyright (c) 2003-2006, 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"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/ioctl.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <pcap.h>
+#ifndef CONFIG_WINPCAP
+#include <dnet.h>
+#endif /* CONFIG_WINPCAP */
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct l2_packet_data {
+ pcap_t *pcap;
+#ifdef CONFIG_WINPCAP
+ unsigned int num_fast_poll;
+#else /* CONFIG_WINPCAP */
+ eth_t *eth;
+#endif /* CONFIG_WINPCAP */
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls
+ * to rx_callback */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static int l2_packet_init_libdnet(struct l2_packet_data *l2)
+{
+ eth_addr_t own_addr;
+
+ l2->eth = eth_open(l2->ifname);
+ if (!l2->eth) {
+ wpa_printf(MSG_ERROR,
+ "Failed to open interface '%s' - eth_open: %s",
+ l2->ifname, strerror(errno));
+ return -1;
+ }
+
+ if (eth_get(l2->eth, &own_addr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Failed to get own hw address from interface '%s' - eth_get: %s",
+ l2->ifname, strerror(errno));
+ eth_close(l2->eth);
+ l2->eth = NULL;
+ return -1;
+ }
+ os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN);
+
+ return 0;
+}
+#endif /* CONFIG_WINPCAP */
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+ struct l2_ethhdr *eth;
+
+ if (l2 == NULL)
+ return -1;
+
+ if (l2->l2_hdr) {
+#ifdef CONFIG_WINPCAP
+ ret = pcap_sendpacket(l2->pcap, buf, len);
+#else /* CONFIG_WINPCAP */
+ ret = eth_send(l2->eth, buf, len);
+#endif /* CONFIG_WINPCAP */
+ } else {
+ size_t mlen = sizeof(*eth) + len;
+ eth = os_malloc(mlen);
+ if (eth == NULL)
+ return -1;
+
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+
+#ifdef CONFIG_WINPCAP
+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+#else /* CONFIG_WINPCAP */
+ ret = eth_send(l2->eth, (u8 *) eth, mlen);
+#endif /* CONFIG_WINPCAP */
+
+ os_free(eth);
+ }
+
+ return ret;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ pcap_t *pcap = sock_ctx;
+ struct pcap_pkthdr hdr;
+ const u_char *packet;
+ struct l2_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ packet = pcap_next(pcap, &hdr);
+
+ if (!l2->rx_callback || !packet || hdr.caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) packet;
+ if (l2->l2_hdr) {
+ buf = (unsigned char *) ethhdr;
+ len = hdr.caplen;
+ } else {
+ buf = (unsigned char *) (ethhdr + 1);
+ len = hdr.caplen - sizeof(*ethhdr);
+ }
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+#ifdef CONFIG_WINPCAP
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+ const u_char *pkt_data)
+{
+ struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+ struct l2_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ if (!l2->rx_callback || !pkt_data || hdr->caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) pkt_data;
+ if (l2->l2_hdr) {
+ buf = (unsigned char *) ethhdr;
+ len = hdr->caplen;
+ } else {
+ buf = (unsigned char *) (ethhdr + 1);
+ len = hdr->caplen - sizeof(*ethhdr);
+ }
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+ /*
+ * Use shorter poll interval for 3 seconds to reduce latency during key
+ * handshake.
+ */
+ l2->num_fast_poll = 3 * 50;
+}
+
+
+static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ pcap_t *pcap = timeout_ctx;
+ int timeout;
+
+ if (l2->num_fast_poll > 0) {
+ timeout = 20000;
+ l2->num_fast_poll--;
+ } else
+ timeout = 100000;
+
+ /* Register new timeout before calling l2_packet_receive() since
+ * receive handler may free this l2_packet instance (which will
+ * cancel this timeout). */
+ eloop_register_timeout(0, timeout, l2_packet_receive_timeout,
+ l2, pcap);
+ pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+#ifdef CONFIG_WINPCAP
+ char ifname[128];
+ os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname);
+ pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", ifname);
+ return -1;
+ }
+ if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
+ fprintf(stderr, "pcap_setnonblock: %s\n",
+ pcap_geterr(l2->pcap));
+#else /* CONFIG_WINPCAP */
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
+ pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
+ fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
+ pcap_geterr(l2->pcap));
+ return -1;
+ }
+#endif /* CONFIG_WINPCAP */
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "not ether src " MACSTR " and "
+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+ "ether proto 0x%x",
+ MAC2STR(l2->own_addr), /* do not receive own packets */
+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+ protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+#ifdef BIOCIMMEDIATE
+ /*
+ * When libpcap uses BPF we must enable "immediate mode" to
+ * receive frames right away; otherwise the system may
+ * buffer them for us.
+ */
+ {
+ unsigned int on = 1;
+ if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
+ fprintf(stderr, "%s: cannot enable immediate mode on "
+ "interface %s: %s\n",
+ __func__, l2->ifname, strerror(errno));
+ /* XXX should we fail? */
+ }
+ }
+#endif /* BIOCIMMEDIATE */
+
+#ifdef CONFIG_WINPCAP
+ eloop_register_timeout(0, 100000, l2_packet_receive_timeout,
+ l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+ l2_packet_receive, l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+#ifdef CONFIG_WINPCAP
+ if (own_addr)
+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+#else /* CONFIG_WINPCAP */
+ if (l2_packet_init_libdnet(l2))
+ return NULL;
+#endif /* CONFIG_WINPCAP */
+
+ if (l2_packet_init_libpcap(l2, protocol)) {
+#ifndef CONFIG_WINPCAP
+ eth_close(l2->eth);
+#endif /* CONFIG_WINPCAP */
+ os_free(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+#ifdef CONFIG_WINPCAP
+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+ if (l2->eth)
+ eth_close(l2->eth);
+ eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
+#endif /* CONFIG_WINPCAP */
+ if (l2->pcap)
+ pcap_close(l2->pcap);
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ pcap_if_t *devs, *dev;
+ struct pcap_addr *addr;
+ struct sockaddr_in *saddr;
+ int found = 0;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+ return -1;
+ }
+
+ for (dev = devs; dev && !found; dev = dev->next) {
+ if (os_strcmp(dev->name, l2->ifname) != 0)
+ continue;
+
+ addr = dev->addresses;
+ while (addr) {
+ saddr = (struct sockaddr_in *) addr->addr;
+ if (saddr && saddr->sin_family == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+ len);
+ found = 1;
+ break;
+ }
+ addr = addr->next;
+ }
+ }
+
+ pcap_freealldevs(devs);
+
+ return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+#ifdef CONFIG_WINPCAP
+ /*
+ * Use shorter poll interval for 3 seconds to reduce latency during key
+ * handshake.
+ */
+ l2->num_fast_poll = 3 * 50;
+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+ eloop_register_timeout(0, 10000, l2_packet_receive_timeout,
+ l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_privsep.c b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
index ce86802c2353..014a45f342b4 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_privsep.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
@@ -216,7 +216,8 @@ struct l2_packet_data * l2_packet_init(
}
os_memcpy(l2->own_addr, reply, ETH_ALEN);
- eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+ if (rx_callback)
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
diff --git a/contrib/wpa/src/l2_packet/l2_packet_winpcap.c b/contrib/wpa/src/l2_packet/l2_packet_winpcap.c
new file mode 100644
index 000000000000..3452051f5493
--- /dev/null
+++ b/contrib/wpa/src/l2_packet/l2_packet_winpcap.c
@@ -0,0 +1,350 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with WinPcap RX thread
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This l2_packet implementation is explicitly for WinPcap and Windows events.
+ * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive
+ * frames which means relatively long latency for EAPOL RX processing. The
+ * implementation here uses a separate thread to allow WinPcap to be receiving
+ * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms
+ * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms
+ * is added in to receive thread whenever no EAPOL frames has been received for
+ * a while. Whenever an EAPOL handshake is expected, this sleep is removed.
+ *
+ * The RX thread receives a frame and signals main thread through Windows event
+ * about the availability of a new frame. Processing the received frame is
+ * synchronized with pair of Windows events so that no extra buffer or queuing
+ * mechanism is needed. This implementation requires Windows specific event
+ * loop implementation, i.e., eloop_win.c.
+ *
+ * WinPcap has pcap_getevent() that could, in theory at least, be used to
+ * implement this kind of waiting with a simpler single-thread design. However,
+ * that event handle is not really signaled immediately when receiving each
+ * frame, so it does not really work for this kind of use.
+ */
+
+#include "includes.h"
+#include <pcap.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+/*
+ * Number of pcap_dispatch() iterations to do without extra wait after each
+ * received EAPOL packet or authentication notification. This is used to reduce
+ * latency for EAPOL receive.
+ */
+static const size_t no_wait_count = 750;
+
+struct l2_packet_data {
+ pcap_t *pcap;
+ unsigned int num_fast_poll;
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
+ * rx_callback and l2_packet_send() */
+ int running;
+ HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
+ u8 *rx_buf, *rx_src;
+ size_t rx_len;
+ size_t rx_no_wait;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+ struct l2_ethhdr *eth;
+
+ if (l2 == NULL)
+ return -1;
+
+ if (l2->l2_hdr) {
+ ret = pcap_sendpacket(l2->pcap, buf, len);
+ } else {
+ size_t mlen = sizeof(*eth) + len;
+ eth = os_malloc(mlen);
+ if (eth == NULL)
+ return -1;
+
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+ os_free(eth);
+ }
+
+ return ret;
+}
+
+
+/* pcap_dispatch() callback for the RX thread */
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+ const u_char *pkt_data)
+{
+ struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+ struct l2_ethhdr *ethhdr;
+
+ if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) pkt_data;
+ if (l2->l2_hdr) {
+ l2->rx_buf = (u8 *) ethhdr;
+ l2->rx_len = hdr->caplen;
+ } else {
+ l2->rx_buf = (u8 *) (ethhdr + 1);
+ l2->rx_len = hdr->caplen - sizeof(*ethhdr);
+ }
+ l2->rx_src = ethhdr->h_source;
+ SetEvent(l2->rx_avail);
+ WaitForSingleObject(l2->rx_done, INFINITE);
+ ResetEvent(l2->rx_done);
+ l2->rx_no_wait = no_wait_count;
+}
+
+
+/* main RX loop that is running in a separate thread */
+static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
+{
+ struct l2_packet_data *l2 = arg;
+
+ while (l2->running) {
+ pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
+ (u_char *) l2);
+ if (l2->rx_no_wait > 0)
+ l2->rx_no_wait--;
+ if (WaitForSingleObject(l2->rx_notify,
+ l2->rx_no_wait ? 0 : 50) ==
+ WAIT_OBJECT_0) {
+ l2->rx_no_wait = no_wait_count;
+ ResetEvent(l2->rx_notify);
+ }
+ }
+ SetEvent(l2->rx_thread_done);
+ ExitThread(0);
+ return 0;
+}
+
+
+/* main thread RX event handler */
+static void l2_packet_rx_event(void *eloop_data, void *user_data)
+{
+ struct l2_packet_data *l2 = eloop_data;
+ l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
+ l2->rx_len);
+ ResetEvent(l2->rx_avail);
+ SetEvent(l2->rx_done);
+}
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "not ether src " MACSTR " and "
+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+ "ether proto 0x%x",
+ MAC2STR(l2->own_addr), /* do not receive own packets */
+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+ protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+ DWORD thread_id;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ else
+ os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
+ ifname);
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ if (own_addr)
+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+
+ if (l2_packet_init_libpcap(l2, protocol)) {
+ os_free(l2);
+ return NULL;
+ }
+
+ if (!rx_callback)
+ return l2;
+
+ l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+ l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+ l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (l2->rx_avail == NULL || l2->rx_done == NULL ||
+ l2->rx_notify == NULL) {
+ CloseHandle(l2->rx_avail);
+ CloseHandle(l2->rx_done);
+ CloseHandle(l2->rx_notify);
+ pcap_close(l2->pcap);
+ os_free(l2);
+ return NULL;
+ }
+
+ eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
+ l2_packet_rx_event, l2, NULL);
+
+ l2->running = 1;
+ l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
+ &thread_id);
+
+ return l2;
+}
+
+
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
+static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+
+ if (l2->rx_thread_done &&
+ WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
+ wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
+ "exit - kill it\n");
+ TerminateThread(l2->rx_thread, 0);
+ }
+ CloseHandle(l2->rx_thread_done);
+ CloseHandle(l2->rx_thread);
+ if (l2->pcap)
+ pcap_close(l2->pcap);
+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+ CloseHandle(l2->rx_avail);
+ CloseHandle(l2->rx_done);
+ CloseHandle(l2->rx_notify);
+ os_free(l2);
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ l2->running = 0;
+ pcap_breakloop(l2->pcap);
+
+ /*
+ * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
+ * event and this event is set in l2_packet_rx_event(). However,
+ * l2_packet_deinit() may end up being called from l2->rx_callback(),
+ * so we need to return from here and complete deinitialization in
+ * a registered timeout to avoid having to forcefully kill the RX
+ * thread.
+ */
+ eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ pcap_if_t *devs, *dev;
+ struct pcap_addr *addr;
+ struct sockaddr_in *saddr;
+ int found = 0;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+ return -1;
+ }
+
+ for (dev = devs; dev && !found; dev = dev->next) {
+ if (os_strcmp(dev->name, l2->ifname) != 0)
+ continue;
+
+ addr = dev->addresses;
+ while (addr) {
+ saddr = (struct sockaddr_in *) addr->addr;
+ if (saddr && saddr->sin_family == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+ len);
+ found = 1;
+ break;
+ }
+ addr = addr->next;
+ }
+ }
+
+ pcap_freealldevs(devs);
+
+ return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+ if (l2)
+ SetEvent(l2->rx_notify);
+}
diff --git a/contrib/wpa/src/lib.rules b/contrib/wpa/src/lib.rules
new file mode 100644
index 000000000000..947617b079d6
--- /dev/null
+++ b/contrib/wpa/src/lib.rules
@@ -0,0 +1,29 @@
+_LIBMK := $(lastword $(wordlist 1,$(shell expr $(words $(MAKEFILE_LIST)) - 1),$(MAKEFILE_LIST)))
+_LIBNAME := $(notdir $(patsubst %/,%,$(dir $(abspath $(_LIBMK)))))
+ALL := $(OUT)lib$(_LIBNAME).a
+LIB_RULES := $(lastword $(MAKEFILE_LIST))
+include $(dir $(LIB_RULES))build.rules
+
+ifdef TEST_FUZZ
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+CFLAGS += -DTEST_FUZZ
+endif
+
+CFLAGS += $(FUZZ_CFLAGS)
+CFLAGS += -I.. -I../utils
+
+_OBJS_VAR := LIB_OBJS
+include ../objs.mk
+
+$(ALL): $(LIB_OBJS)
+ @$(E) " AR $(notdir $@)"
+ $(Q)$(AR) crT $@ $?
+
+install-default:
+ @echo Nothing to be made.
+
+%: %-default
+ @true
+
+clean: common-clean
+ $(Q)rm -f *~ *.o *.d *.gcno *.gcda *.gcov $(ALL)
diff --git a/contrib/wpa/src/objs.mk b/contrib/wpa/src/objs.mk
new file mode 100644
index 000000000000..a3040b21bd94
--- /dev/null
+++ b/contrib/wpa/src/objs.mk
@@ -0,0 +1,3 @@
+$(_OBJS_VAR) := $(call BUILDOBJ,$($(_OBJS_VAR)))
+-include $(filter-out %.a,$($(_OBJS_VAR):%.o=%.d))
+_DIRS += $(dir $($(_OBJS_VAR)))
diff --git a/contrib/wpa/src/p2p/Makefile b/contrib/wpa/src/p2p/Makefile
new file mode 100644
index 000000000000..4d1618006c68
--- /dev/null
+++ b/contrib/wpa/src/p2p/Makefile
@@ -0,0 +1,16 @@
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WPS_NFC
+
+LIB_OBJS= \
+ p2p_build.o \
+ p2p.o \
+ p2p_dev_disc.o \
+ p2p_go_neg.o \
+ p2p_group.o \
+ p2p_invitation.o \
+ p2p_parse.o \
+ p2p_pd.o \
+ p2p_sd.o \
+ p2p_utils.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/p2p/p2p.c b/contrib/wpa/src/p2p/p2p.c
index a08ba02686c6..9ac505735cbb 100644
--- a/contrib/wpa/src/p2p/p2p.c
+++ b/contrib/wpa/src/p2p/p2p.c
@@ -428,7 +428,9 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
oldest = dev;
}
if (count + 1 > p2p->cfg->max_peers && oldest) {
- p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
+ p2p_dbg(p2p,
+ "Remove oldest peer entry to make room for a new peer "
+ MACSTR, MAC2STR(oldest->info.p2p_device_addr));
dl_list_del(&oldest->list);
p2p_device_free(p2p, oldest);
}
@@ -453,6 +455,8 @@ static void p2p_copy_client_info(struct p2p_device *dev,
dev->info.config_methods = cli->config_methods;
os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types;
+ if (dev->info.wps_sec_dev_type_list_len > WPS_SEC_DEV_TYPE_MAX_LEN)
+ dev->info.wps_sec_dev_type_list_len = WPS_SEC_DEV_TYPE_MAX_LEN;
os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types,
dev->info.wps_sec_dev_type_list_len);
}
@@ -663,6 +667,8 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
break;
wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ if (wpabuf_size(dev->info.vendor_elems) > 2000)
+ break;
}
}
@@ -1029,7 +1035,7 @@ static void p2p_search(struct p2p_data *p2p)
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, pw_id);
+ p2p->find_dev_id, pw_id, p2p->include_6ghz);
if (res < 0) {
p2p_dbg(p2p, "Scan request schedule failed");
p2p_continue_find(p2p);
@@ -1153,7 +1159,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_count, const char **seek, int freq)
+ u8 seek_count, const char **seek, int freq, bool include_6ghz)
{
int res;
struct os_reltime start;
@@ -1178,7 +1184,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p->find_dev_id = p2p->find_dev_id_buf;
} else
p2p->find_dev_id = NULL;
-
+ p2p->include_6ghz = p2p_wfd_enabled(p2p) && include_6ghz;
if (seek_count == 0 || !seek) {
/* Not an ASP search */
p2p->p2ps_seek = 0;
@@ -1254,7 +1260,8 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
P2P_SCAN_SPECIFIC, freq,
p2p->num_req_dev_types,
p2p->req_dev_types, dev_id,
- DEV_PW_DEFAULT);
+ DEV_PW_DEFAULT,
+ p2p->include_6ghz);
break;
}
/* fall through */
@@ -1262,13 +1269,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
p2p->req_dev_types, dev_id,
- DEV_PW_DEFAULT);
+ DEV_PW_DEFAULT, p2p->include_6ghz);
break;
case P2P_FIND_ONLY_SOCIAL:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
p2p->num_req_dev_types,
p2p->req_dev_types, dev_id,
- DEV_PW_DEFAULT);
+ DEV_PW_DEFAULT, p2p->include_6ghz);
break;
default:
return -1;
@@ -1390,8 +1397,8 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
} else {
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
+ p2p_copy_channels(&p2p->channels, &p2p->cfg->channels,
+ p2p->allow_6ghz);
}
return 0;
@@ -1404,6 +1411,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 0 };
+ const int op_classes_edmg[] = { 181, 182, 183, 0 };
+ const int op_classes_6ghz[] = { 131, 0 };
p2p_dbg(p2p, "Prepare channel best");
@@ -1435,6 +1444,17 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_edmg,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible EDMG channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p->allow_6ghz &&
+ (p2p_channel_select(&p2p->cfg->channels, op_classes_6ghz,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0)) {
+ p2p_dbg(p2p, "Select possible 6 GHz channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
&p2p->op_reg_class, &p2p->op_channel) ==
0) {
@@ -1472,8 +1492,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
p2p->op_channel, p2p->op_reg_class);
}
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
+ p2p_copy_channels(&p2p->channels, &p2p->cfg->channels, p2p->allow_6ghz);
}
@@ -1556,9 +1575,10 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
" wps_method=%d persistent_group=%d pd_before_go_neg=%d "
- "oob_pw_id=%u",
+ "oob_pw_id=%u allow_6ghz=%d",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
+ wps_method, persistent_group, pd_before_go_neg, oob_pw_id,
+ p2p->allow_6ghz);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
@@ -1656,9 +1676,9 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d oob_pw_id=%u",
+ " wps_method=%d persistent_group=%d oob_pw_id=%u allow_6ghz=%d",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group, oob_pw_id);
+ wps_method, persistent_group, oob_pw_id, p2p->allow_6ghz);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
@@ -2907,6 +2927,14 @@ void p2p_group_formation_failed(struct p2p_data *p2p)
}
+bool is_p2p_6ghz_disabled(struct p2p_data *p2p)
+{
+ if (p2p)
+ return p2p->cfg->p2p_6ghz_disable;
+ return false;
+}
+
+
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
@@ -3451,12 +3479,18 @@ static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
- if (!success)
+ if (!success) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
return;
+ }
if (!p2p->cfg->prov_disc_resp_cb ||
- p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
+ p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
return;
+ }
p2p_dbg(p2p,
"Post-Provision Discovery operations started - do not try to continue other P2P operations");
@@ -3490,12 +3524,17 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
}
-void p2p_scan_res_handled(struct p2p_data *p2p)
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay)
{
if (!p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
}
p2p->p2p_scan_running = 0;
+
+ /* Use this delay only when p2p_find doesn't set it */
+ if (!p2p->search_delay)
+ p2p->search_delay = delay;
+
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
if (p2p_run_after_scan(p2p))
@@ -3962,6 +4001,11 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
}
p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for %s", __func__);
+ p2p->pending_listen_freq = 0;
+ }
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
}
@@ -4915,6 +4959,7 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
buf, len, wait_time, &scheduled);
if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
+ p2p->drv_in_listen > 0 &&
(unsigned int) p2p->drv_in_listen != freq) {
p2p_dbg(p2p,
"Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
@@ -5538,3 +5583,69 @@ struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
return buf;
}
+
+
+bool p2p_is_peer_6ghz_capab(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev)
+ return false;
+
+ return !!(dev->info.dev_capab & P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE);
+}
+
+
+void p2p_set_6ghz_dev_capab(struct p2p_data *p2p, bool allow_6ghz)
+{
+ p2p->p2p_6ghz_capable = allow_6ghz;
+ p2p->allow_6ghz = allow_6ghz;
+ p2p_dbg(p2p, "Set 6 GHz capability to %d", allow_6ghz);
+
+ if (allow_6ghz)
+ p2p->dev_capab |= P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE;
+ else
+ p2p->dev_capab &= ~P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE;
+}
+
+
+bool is_p2p_6ghz_capable(struct p2p_data *p2p)
+{
+ return p2p->p2p_6ghz_capable;
+}
+
+
+bool p2p_wfd_enabled(struct p2p_data *p2p)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+ return p2p->wfd_ie_probe_req != NULL;
+#else /* CONFIG_WIFI_DISPLAY */
+ return false;
+#endif /* CONFIG_WIFI_DISPLAY */
+}
+
+
+bool p2p_peer_wfd_enabled(struct p2p_data *p2p, const u8 *peer_addr)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, peer_addr);
+ return dev && dev->info.wfd_subelems != NULL;
+#else /* CONFIG_WIFI_DISPLAY */
+ return false;
+#endif /* CONFIG_WIFI_DISPLAY */
+}
+
+
+bool is_p2p_allow_6ghz(struct p2p_data *p2p)
+{
+ return p2p->allow_6ghz;
+}
+
+
+void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value)
+{
+ p2p->allow_6ghz = value;
+}
diff --git a/contrib/wpa/src/p2p/p2p.h b/contrib/wpa/src/p2p/p2p.h
index 425b037be515..f606fbb14a81 100644
--- a/contrib/wpa/src/p2p/p2p.h
+++ b/contrib/wpa/src/p2p/p2p.h
@@ -36,7 +36,7 @@
/**
* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
*/
-#define P2P_MAX_REG_CLASS_CHANNELS 20
+#define P2P_MAX_REG_CLASS_CHANNELS 60
/**
* struct p2p_channels - List of supported channels
@@ -99,6 +99,8 @@ struct p2p_go_neg_results {
int vht;
+ int edmg;
+
u8 max_oper_chwidth;
unsigned int vht_center_freq2;
@@ -499,6 +501,11 @@ struct p2p_config {
struct p2p_channel *pref_chan;
/**
+ * p2p_6ghz_disable - Disable 6GHz for P2P operations
+ */
+ bool p2p_6ghz_disable;
+
+ /**
* pri_dev_type - Primary Device Type (see WPS)
*/
u8 pri_dev_type[8];
@@ -605,6 +612,7 @@ struct p2p_config {
* @req_dev_types: Array containing requested device types
* @dev_id: Device ID to search for or %NULL to find all devices
* @pw_id: Device Password ID
+ * @include_6ghz: Include 6 GHz channels in P2P scan
* Returns: 0 on success, -1 on failure
*
* This callback function is used to request a P2P scan or search
@@ -628,7 +636,8 @@ struct p2p_config {
*/
int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
- const u8 *req_dev_types, const u8 *dev_id, u16 pw_id);
+ const u8 *req_dev_types, const u8 *dev_id, u16 pw_id,
+ bool include_6ghz);
/**
* send_probe_resp - Transmit a Probe Response frame
@@ -1236,13 +1245,15 @@ enum p2p_discovery_type {
* P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan.
* If p2p_find is already in progress, this parameter is ignored and full
* scan will be executed.
+ * @include_6ghz: Include 6 GHz channels in P2P find
* Returns: 0 on success, -1 on failure
*/
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_count, const char **seek_string, int freq);
+ u8 seek_count, const char **seek_string, int freq,
+ bool include_6ghz);
/**
* p2p_notify_scan_trigger_status - Indicate scan trigger status
@@ -1618,6 +1629,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
/**
* p2p_scan_res_handled - Indicate end of scan results
* @p2p: P2P module context from p2p_init()
+ * @delay: Search delay for next scan in ms
*
* This function is called to indicate that all P2P scan results from a scan
* have been reported with zero or more calls to p2p_scan_res_handler(). This
@@ -1625,7 +1637,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
* struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler()
* calls stopped iteration.
*/
-void p2p_scan_res_handled(struct p2p_data *p2p);
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay);
enum p2p_send_action_result {
P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
@@ -2098,6 +2110,8 @@ void p2p_update_channel_list(struct p2p_data *p2p,
const struct p2p_channels *chan,
const struct p2p_channels *cli_chan);
+bool is_p2p_6ghz_disabled(struct p2p_data *p2p);
+
/**
* p2p_set_best_channels - Update best channel information
* @p2p: P2P module context from p2p_init()
@@ -2401,4 +2415,13 @@ int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
unsigned int freq);
+void p2p_set_6ghz_dev_capab(struct p2p_data *p2p, bool allow_6ghz);
+bool is_p2p_6ghz_capable(struct p2p_data *p2p);
+bool p2p_is_peer_6ghz_capab(struct p2p_data *p2p, const u8 *addr);
+bool p2p_peer_wfd_enabled(struct p2p_data *p2p, const u8 *peer_addr);
+bool p2p_wfd_enabled(struct p2p_data *p2p);
+bool is_p2p_allow_6ghz(struct p2p_data *p2p);
+void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
+int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size);
+
#endif /* P2P_H */
diff --git a/contrib/wpa/src/p2p/p2p_go_neg.c b/contrib/wpa/src/p2p/p2p_go_neg.c
index c94bf41a7081..113346141986 100644
--- a/contrib/wpa/src/p2p/p2p_go_neg.c
+++ b/contrib/wpa/src/p2p/p2p_go_neg.c
@@ -390,6 +390,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 129, 130, 0 };
+ const int op_classes_edmg[] = { 181, 182, 183, 0 };
if (p2p->own_freq_preference > 0 &&
p2p_freq_to_channel(p2p->own_freq_preference,
@@ -454,6 +455,14 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
}
+ /* Try a channel where we might be able to use EDMG */
+ if (p2p_channel_select(intersection, op_classes_edmg,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible EDMG channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/* Try a channel where we might be able to use VHT */
if (p2p_channel_select(intersection, op_classes_vht,
&p2p->op_reg_class, &p2p->op_channel) == 0) {
diff --git a/contrib/wpa/src/p2p/p2p_i.h b/contrib/wpa/src/p2p/p2p_i.h
index 4195c5f07dd1..8220e85506a3 100644
--- a/contrib/wpa/src/p2p/p2p_i.h
+++ b/contrib/wpa/src/p2p/p2p_i.h
@@ -548,6 +548,9 @@ struct p2p_data {
/* Override option for preferred operating channel in GO Negotiation */
u8 override_pref_op_class;
u8 override_pref_channel;
+ bool p2p_6ghz_capable;
+ bool include_6ghz;
+ bool allow_6ghz;
};
/**
@@ -698,6 +701,8 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
u8 *op_channel,
struct wpa_freq_range_list *avoid_list,
struct wpa_freq_range_list *disallow_list);
+void p2p_copy_channels(struct p2p_channels *dst, const struct p2p_channels *src,
+ bool allow_6ghz);
/* p2p_parse.c */
void p2p_copy_filter_devname(char *dst, size_t dst_len,
diff --git a/contrib/wpa/src/p2p/p2p_invitation.c b/contrib/wpa/src/p2p/p2p_invitation.c
index 77d662a47ae2..ab0072219d2e 100644
--- a/contrib/wpa/src/p2p/p2p_invitation.c
+++ b/contrib/wpa/src/p2p/p2p_invitation.c
@@ -653,8 +653,9 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
struct p2p_device *dev;
p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
- "force_freq=%u",
- MAC2STR(peer), role, persistent_group, force_freq);
+ "force_freq=%u allow_6ghz=%d",
+ MAC2STR(peer), role, persistent_group, force_freq,
+ p2p->allow_6ghz);
if (bssid)
p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
if (go_dev_addr) {
diff --git a/contrib/wpa/src/p2p/p2p_utils.c b/contrib/wpa/src/p2p/p2p_utils.c
index 1a62a44a2df3..7d21f68819c7 100644
--- a/contrib/wpa/src/p2p/p2p_utils.c
+++ b/contrib/wpa/src/p2p/p2p_utils.c
@@ -496,3 +496,42 @@ int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
return idx;
}
+
+
+void p2p_copy_channels(struct p2p_channels *dst,
+ const struct p2p_channels *src, bool allow_6ghz)
+{
+ size_t i, j;
+
+ if (allow_6ghz) {
+ os_memcpy(dst, src, sizeof(struct p2p_channels));
+ return;
+ }
+
+ for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) {
+ if (is_6ghz_op_class(src->reg_class[i].reg_class))
+ continue;
+ os_memcpy(&dst->reg_class[j], &src->reg_class[i],
+ sizeof(struct p2p_reg_class));
+ j++;
+ }
+ dst->reg_classes = j;
+}
+
+
+int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (is_6ghz_freq(pref_freq_list[i])) {
+ wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d",
+ pref_freq_list[i]);
+ size--;
+ os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1],
+ (size - i) * sizeof(pref_freq_list[0]));
+ i--;
+ }
+ }
+ return i;
+}
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.c b/contrib/wpa/src/pae/ieee802_1x_cp.c
index 1c4dc3e63c9f..cf41d8dbf2f9 100644
--- a/contrib/wpa/src/pae/ieee802_1x_cp.c
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.c
@@ -31,50 +31,50 @@ struct ieee802_1x_cp_sm {
CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
} CP_state;
- Boolean changed;
+ bool changed;
/* CP -> Client */
- Boolean port_valid;
+ bool port_valid;
/* Logon -> CP */
enum connect_type connect;
/* KaY -> CP */
- Boolean chgd_server; /* clear by CP */
- Boolean elected_self;
+ bool chgd_server; /* clear by CP */
+ bool elected_self;
enum confidentiality_offset cipher_offset;
u64 cipher_suite;
- Boolean new_sak; /* clear by CP */
+ bool new_sak; /* clear by CP */
struct ieee802_1x_mka_ki distributed_ki;
u8 distributed_an;
- Boolean using_receive_sas;
- Boolean all_receiving;
- Boolean server_transmitting;
- Boolean using_transmit_sa;
+ bool using_receive_sas;
+ bool all_receiving;
+ bool server_transmitting;
+ bool using_transmit_sa;
/* CP -> KaY */
struct ieee802_1x_mka_ki *lki;
u8 lan;
- Boolean ltx;
- Boolean lrx;
+ bool ltx;
+ bool lrx;
struct ieee802_1x_mka_ki *oki;
u8 oan;
- Boolean otx;
- Boolean orx;
+ bool otx;
+ bool orx;
/* CP -> SecY */
- Boolean protect_frames;
+ bool protect_frames;
enum validate_frames validate_frames;
- Boolean replay_protect;
+ bool replay_protect;
u32 replay_window;
u64 current_cipher_suite;
enum confidentiality_offset confidentiality_offset;
- Boolean controlled_port_enabled;
+ bool controlled_port_enabled;
/* SecY -> CP */
- Boolean port_enabled; /* SecY->CP */
+ bool port_enabled; /* SecY->CP */
/* private */
u32 transmit_when;
@@ -109,23 +109,23 @@ SM_STATE(CP, INIT)
{
SM_ENTRY(CP, INIT);
- sm->controlled_port_enabled = FALSE;
+ sm->controlled_port_enabled = false;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
- sm->port_valid = FALSE;
+ sm->port_valid = false;
os_free(sm->lki);
sm->lki = NULL;
- sm->ltx = FALSE;
- sm->lrx = FALSE;
+ sm->ltx = false;
+ sm->lrx = false;
os_free(sm->oki);
sm->oki = NULL;
- sm->otx = FALSE;
- sm->orx = FALSE;
+ sm->otx = false;
+ sm->orx = false;
- sm->port_enabled = TRUE;
- sm->chgd_server = FALSE;
+ sm->port_enabled = true;
+ sm->chgd_server = false;
}
@@ -133,14 +133,32 @@ SM_STATE(CP, CHANGE)
{
SM_ENTRY(CP, CHANGE);
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = FALSE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = false;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
if (sm->lki)
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
if (sm->oki)
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ /* The standard doesn't say it but we should clear out the latest
+ * and old key values. Why would we keep advertising them if
+ * they've been deleted and the key server has been changed?
+ */
+ os_free(sm->oki);
+ sm->oki = NULL;
+ sm->otx = false;
+ sm->orx = false;
+ sm->oan = 0;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+ os_free(sm->lki);
+ sm->lki = NULL;
+ sm->lrx = false;
+ sm->ltx = false;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -148,12 +166,12 @@ SM_STATE(CP, ALLOWED)
{
SM_ENTRY(CP, ALLOWED);
- sm->protect_frames = FALSE;
- sm->replay_protect = FALSE;
+ sm->protect_frames = false;
+ sm->replay_protect = false;
sm->validate_frames = Checked;
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = TRUE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
@@ -167,12 +185,12 @@ SM_STATE(CP, AUTHENTICATED)
{
SM_ENTRY(CP, AUTHENTICATED);
- sm->protect_frames = FALSE;
- sm->replay_protect = FALSE;
+ sm->protect_frames = false;
+ sm->replay_protect = false;
sm->validate_frames = Checked;
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = TRUE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
@@ -186,7 +204,7 @@ SM_STATE(CP, SECURED)
{
SM_ENTRY(CP, SECURED);
- sm->chgd_server = FALSE;
+ sm->chgd_server = false;
sm->protect_frames = sm->kay->macsec_protect;
sm->replay_protect = sm->kay->macsec_replay_protect;
@@ -198,7 +216,7 @@ SM_STATE(CP, SECURED)
sm->confidentiality_offset = sm->cipher_offset;
- sm->port_valid = TRUE;
+ sm->port_valid = true;
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
@@ -212,18 +230,6 @@ SM_STATE(CP, SECURED)
SM_STATE(CP, RECEIVE)
{
SM_ENTRY(CP, RECEIVE);
- /* RECEIVE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
- if (sm->oki) {
- ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
- os_free(sm->oki);
- }
- sm->oki = sm->lki;
- sm->oan = sm->lan;
- sm->otx = sm->ltx;
- sm->orx = sm->lrx;
- ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
- sm->otx, sm->orx);
sm->lki = os_malloc(sizeof(*sm->lki));
if (!sm->lki) {
@@ -232,14 +238,14 @@ SM_STATE(CP, RECEIVE)
}
os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
sm->lan = sm->distributed_an;
- sm->ltx = FALSE;
- sm->lrx = FALSE;
+ sm->ltx = false;
+ sm->lrx = false;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_create_sas(sm->kay, sm->lki);
ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
- sm->new_sak = FALSE;
- sm->all_receiving = FALSE;
+ sm->new_sak = false;
+ sm->all_receiving = false;
}
@@ -247,7 +253,7 @@ SM_STATE(CP, RECEIVING)
{
SM_ENTRY(CP, RECEIVING);
- sm->lrx = TRUE;
+ sm->lrx = true;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
sm->transmit_when = sm->transmit_delay;
@@ -258,8 +264,8 @@ SM_STATE(CP, RECEIVING)
* but the CP will transmit from RECEIVING to READY under
* the !electedSelf when KaY is not key server */
ieee802_1x_cp_sm_step(sm);
- sm->using_receive_sas = FALSE;
- sm->server_transmitting = FALSE;
+ sm->using_receive_sas = false;
+ sm->server_transmitting = false;
}
@@ -275,14 +281,14 @@ SM_STATE(CP, TRANSMIT)
{
SM_ENTRY(CP, TRANSMIT);
- sm->controlled_port_enabled = TRUE;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
- sm->ltx = TRUE;
+ sm->ltx = true;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki);
- sm->all_receiving = FALSE;
- sm->server_transmitting = FALSE;
+ sm->all_receiving = false;
+ sm->server_transmitting = false;
}
@@ -290,21 +296,21 @@ SM_STATE(CP, TRANSMITTING)
{
SM_ENTRY(CP, TRANSMITTING);
sm->retire_when = sm->orx ? sm->retire_delay : 0;
- sm->otx = FALSE;
+ sm->otx = false;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
ieee802_1x_kay_enable_new_info(sm->kay);
eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
eloop_register_timeout(sm->retire_when / 1000, 0,
ieee802_1x_cp_retire_when_timeout, sm, NULL);
- sm->using_transmit_sa = FALSE;
+ sm->using_transmit_sa = false;
}
SM_STATE(CP, ABANDON)
{
SM_ENTRY(CP, ABANDON);
- sm->lrx = FALSE;
+ sm->lrx = false;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
@@ -313,24 +319,29 @@ SM_STATE(CP, ABANDON)
sm->lki = NULL;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
- sm->new_sak = FALSE;
}
SM_STATE(CP, RETIRE)
{
SM_ENTRY(CP, RETIRE);
- /* RETIRE state machine not keep with Figure 12-2 in
- * IEEE Std 802.1X-2010 */
if (sm->oki) {
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
os_free(sm->oki);
sm->oki = NULL;
}
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->oki = sm->lki;
+ sm->otx = sm->ltx;
+ sm->orx = sm->lrx;
+ sm->oan = sm->lan;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
+ sm->lki = NULL;
+ sm->ltx = false;
+ sm->lrx = false;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -444,23 +455,23 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
sm->kay = kay;
- sm->port_valid = FALSE;
+ sm->port_valid = false;
- sm->chgd_server = FALSE;
+ sm->chgd_server = false;
sm->protect_frames = kay->macsec_protect;
sm->validate_frames = kay->macsec_validate;
sm->replay_protect = kay->macsec_replay_protect;
sm->replay_window = kay->macsec_replay_window;
- sm->controlled_port_enabled = FALSE;
+ sm->controlled_port_enabled = false;
sm->lki = NULL;
- sm->lrx = FALSE;
- sm->ltx = FALSE;
+ sm->lrx = false;
+ sm->ltx = false;
sm->oki = NULL;
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->orx = false;
+ sm->otx = false;
sm->current_cipher_suite = default_cs_id;
sm->cipher_suite = default_cs_id;
@@ -469,7 +480,7 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
sm->transmit_delay = MKA_LIFE_TIME;
sm->retire_delay = MKA_SAK_RETIRE_TIME;
sm->CP_state = CP_BEGIN;
- sm->changed = FALSE;
+ sm->changed = false;
wpa_printf(MSG_DEBUG, "CP: state machine created");
@@ -577,14 +588,14 @@ void ieee802_1x_cp_signal_chgdserver(void *cp_ctx)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- sm->chgd_server = TRUE;
+ sm->chgd_server = true;
}
/**
* ieee802_1x_cp_set_electedself -
*/
-void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_electedself(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->elected_self = status;
@@ -617,7 +628,7 @@ void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset)
void ieee802_1x_cp_signal_newsak(void *cp_ctx)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- sm->new_sak = TRUE;
+ sm->new_sak = true;
}
@@ -645,7 +656,7 @@ void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an)
/**
* ieee802_1x_cp_set_usingreceivesas -
*/
-void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->using_receive_sas = status;
@@ -655,7 +666,7 @@ void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
/**
* ieee802_1x_cp_set_allreceiving -
*/
-void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->all_receiving = status;
@@ -665,7 +676,7 @@ void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
/**
* ieee802_1x_cp_set_servertransmitting -
*/
-void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->server_transmitting = status;
@@ -675,7 +686,7 @@ void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
/**
* ieee802_1x_cp_set_usingtransmitsas -
*/
-void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->using_transmit_sa = status;
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.h b/contrib/wpa/src/pae/ieee802_1x_cp.h
index a357b278f40a..94110c877164 100644
--- a/contrib/wpa/src/pae/ieee802_1x_cp.h
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.h
@@ -24,16 +24,16 @@ void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx);
void ieee802_1x_cp_connect_authenticated(void *cp_ctx);
void ieee802_1x_cp_connect_secure(void *cp_ctx);
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx);
-void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_electedself(void *cp_ctx, bool status);
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs);
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset);
void ieee802_1x_cp_signal_newsak(void *cp_ctx);
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
const struct ieee802_1x_mka_ki *dki);
void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an);
-void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, bool status);
#endif /* IEEE802_1X_CP_H */
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.c b/contrib/wpa/src/pae/ieee802_1x_kay.c
index a330d0cf4559..2fe88ac0c5f2 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay.c
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.c
@@ -354,7 +354,7 @@ ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
/**
* ieee802_1x_kay_is_in_potential_peer
*/
-static Boolean
+static bool
ieee802_1x_kay_is_in_potential_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
@@ -365,7 +365,7 @@ ieee802_1x_kay_is_in_potential_peer(
/**
* ieee802_1x_kay_is_in_live_peer
*/
-static Boolean
+static bool
ieee802_1x_kay_is_in_live_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
@@ -426,8 +426,8 @@ u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci)
}
-static Boolean sci_equal(const struct ieee802_1x_mka_sci *a,
- const struct ieee802_1x_mka_sci *b)
+static bool sci_equal(const struct ieee802_1x_mka_sci *a,
+ const struct ieee802_1x_mka_sci *b)
{
return os_memcmp(a, b, sizeof(struct ieee802_1x_mka_sci)) == 0;
}
@@ -486,7 +486,7 @@ ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
psa->sc = psc;
os_get_time(&psa->created_time);
- psa->in_use = FALSE;
+ psa->in_use = false;
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
@@ -534,7 +534,7 @@ ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci)
os_memcpy(&psc->sci, psci, sizeof(psc->sci));
os_get_time(&psc->created_time);
- psc->receiving = FALSE;
+ psc->receiving = false;
dl_list_init(&psc->sa_list);
wpa_printf(MSG_DEBUG, "KaY: Create receive SC: SCI %s",
@@ -594,7 +594,7 @@ ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
os_memcpy(peer->mi, mi, MI_LEN);
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- peer->sak_used = FALSE;
+ peer->sak_used = false;
peer->missing_sak_use_count = 0;
return peer;
@@ -706,11 +706,11 @@ ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
/**
* ieee802_1x_mka_basic_body_present -
*/
-static Boolean
+static bool
ieee802_1x_mka_basic_body_present(
struct ieee802_1x_mka_participant *participant)
{
- return TRUE;
+ return true;
}
@@ -774,14 +774,14 @@ ieee802_1x_mka_encode_basic_body(
}
-static Boolean
+static bool
reset_participant_mi(struct ieee802_1x_mka_participant *participant)
{
if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
- return FALSE;
+ return false;
participant->mn = 0;
- return TRUE;
+ return true;
}
@@ -888,13 +888,13 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
- peer->is_key_server = (Boolean) body->key_server;
+ peer->is_key_server = body->key_server;
peer->key_server_priority = body->priority;
} else if (peer->mn < be_to_host32(body->actor_mn)) {
peer->mn = be_to_host32(body->actor_mn);
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
- peer->is_key_server = (Boolean) body->key_server;
+ peer->is_key_server = body->key_server;
peer->key_server_priority = body->priority;
} else {
wpa_printf(MSG_WARNING,
@@ -909,7 +909,7 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
/**
* ieee802_1x_mka_live_peer_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_live_peer_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -969,7 +969,7 @@ ieee802_1x_mka_encode_live_peer_body(
/**
* ieee802_1x_mka_potential_peer_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_potential_peer_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1030,7 +1030,7 @@ ieee802_1x_mka_encode_potential_peer_body(
/**
* ieee802_1x_mka_i_in_peerlist -
*/
-static Boolean
+static bool
ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
@@ -1055,7 +1055,7 @@ ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
left_len, MKA_HDR_LEN,
MKA_ALIGN_LENGTH(body_len),
DEFAULT_ICV_LEN);
- return FALSE;
+ return false;
}
if (body_type != MKA_LIVE_PEER_LIST &&
@@ -1096,12 +1096,12 @@ ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
if (mn == participant->mn ||
(participant->mn > 1 &&
mn == participant->mn - 1))
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
@@ -1116,7 +1116,7 @@ static int ieee802_1x_mka_decode_live_peer_body(
struct ieee802_1x_kay_peer *peer;
size_t body_len;
size_t i;
- Boolean is_included;
+ bool is_included;
is_included = ieee802_1x_kay_is_in_live_peer(
participant, participant->current_peer_id.mi);
@@ -1209,7 +1209,7 @@ ieee802_1x_mka_decode_potential_peer_body(
/**
* ieee802_1x_mka_sak_use_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_sak_use_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1287,7 +1287,7 @@ ieee802_1x_mka_encode_sak_use_body(
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
- u32 pn = 1;
+ u32 olpn, llpn;
length = ieee802_1x_mka_get_sak_use_length(participant);
body = wpabuf_put(buf, length);
@@ -1296,29 +1296,42 @@ ieee802_1x_mka_encode_sak_use_body(
set_mka_param_body_len(body, length - MKA_HDR_LEN);
if (length == MKA_HDR_LEN) {
- body->ptx = TRUE;
- body->prx = TRUE;
+ body->ptx = true;
+ body->prx = true;
body->lan = 0;
- body->lrx = FALSE;
- body->ltx = FALSE;
- body->delay_protect = FALSE;
+ body->lrx = false;
+ body->ltx = false;
+ body->delay_protect = false;
return 0;
}
/* data delay protect */
body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
- /* lowest accept packet number */
- pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
- if (pn > kay->pn_exhaustion) {
- wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
- if (participant->is_key_server)
- participant->new_sak = TRUE;
+ /* lowest accept packet numbers */
+ olpn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
+ body->olpn = host_to_be32(olpn);
+ llpn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
+ body->llpn = host_to_be32(llpn);
+ if (participant->is_key_server) {
+ /* The CP will spend most of it's time in RETIRE where only
+ * the old key is populated. Therefore we should be checking
+ * the OLPN most of the time.
+ */
+ if (participant->lrx) {
+ if (llpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My LLPN exhaustion");
+ participant->new_sak = true;
+ }
+ } else {
+ if (olpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My OLPN exhaustion");
+ participant->new_sak = true;
+ }
+ }
}
- body->llpn = host_to_be32(pn);
- pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
- body->olpn = host_to_be32(pn);
-
/* plain tx, plain rx */
body->ptx = !kay->macsec_protect;
body->prx = kay->macsec_validate != Strict;
@@ -1334,23 +1347,23 @@ ieee802_1x_mka_encode_sak_use_body(
body->oan = participant->oan;
if (participant->oki.kn != participant->lki.kn &&
participant->oki.kn != 0) {
- body->otx = TRUE;
- body->orx = TRUE;
+ body->otx = true;
+ body->orx = true;
os_memcpy(body->osrv_mi, participant->oki.mi,
sizeof(body->osrv_mi));
body->okn = host_to_be32(participant->oki.kn);
} else {
- body->otx = FALSE;
- body->orx = FALSE;
+ body->otx = false;
+ body->orx = false;
}
/* set CP's variable */
if (body->ltx) {
- kay->tx_enable = TRUE;
- kay->port_enable = TRUE;
+ kay->tx_enable = true;
+ kay->port_enable = true;
}
if (body->lrx)
- kay->rx_enable = TRUE;
+ kay->rx_enable = true;
ieee802_1x_mka_dump_sak_use_body(body);
return 0;
@@ -1368,15 +1381,12 @@ ieee802_1x_mka_decode_sak_use_body(
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
u32 lpn;
- Boolean all_receiving;
- Boolean found;
struct ieee802_1x_kay *kay = participant->kay;
+ u32 olpn, llpn;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1417,46 +1427,6 @@ ieee802_1x_mka_decode_sak_use_body(
if (body->ptx)
wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
-
- /* check latest key is valid */
- if (body->ltx || body->lrx) {
- found = FALSE;
- os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = be_to_host32(body->lkn);
- dl_list_for_each(sa_key, &participant->sak_list,
- struct data_key, list) {
- if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
- return -1;
- }
- if (os_memcmp(participant->lki.mi, body->lsrv_mi,
- sizeof(participant->lki.mi)) == 0 &&
- be_to_host32(body->lkn) == participant->lki.kn &&
- body->lan == participant->lan) {
- peer->sak_used = TRUE;
- }
- if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
- }
- }
-
- /* check old key is valid (but only if we remember our old key) */
- if (participant->oki.kn != 0 && (body->otx || body->orx)) {
- if (os_memcmp(participant->oki.mi, body->osrv_mi,
- sizeof(participant->oki.mi)) != 0 ||
- be_to_host32(body->okn) != participant->oki.kn ||
- body->oan != participant->oan) {
- wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
- return -1;
- }
- }
-
/* TODO: how to set the MACsec hardware when delay_protect is true */
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
@@ -1465,65 +1435,132 @@ ieee802_1x_mka_decode_sak_use_body(
return -1;
}
- /* check all live peer have used the sak for receiving sa */
- all_receiving = TRUE;
- dl_list_for_each(peer, &participant->live_peers,
- struct ieee802_1x_kay_peer, list) {
- if (!peer->sak_used) {
- all_receiving = FALSE;
- break;
- }
- }
- if (all_receiving) {
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
+ olpn = be_to_host32(body->olpn);
+ llpn = be_to_host32(body->llpn);
+
+ /* Our most recent distributed key should be the first in the list.
+ * If it doesn't exist then we can't really do anything.
+ * Be lenient and don't return error here as there are legitimate cases
+ * where this can happen such as when a new participant joins the CA and
+ * the first frame it receives can have a SAKuse but not distSAK.
+ */
+ sa_key = dl_list_first(&participant->sak_list, struct data_key, list);
+ if (!sa_key) {
+ wpa_printf(MSG_INFO,
+ "KaY: We don't have a latest distributed key - ignore SAK use");
+ return 0;
}
- /* if I'm key server, and detects peer member pn exhaustion, rekey. */
- lpn = be_to_host32(body->llpn);
- if (lpn > kay->pn_exhaustion) {
- if (participant->is_key_server) {
- participant->new_sak = TRUE;
- wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
- }
+ /* The peer's most recent key will be the "latest key" if it is present
+ * otherwise it will be the "old key" if in the RETIRE state.
+ */
+ if (body->lrx) {
+ os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->lkn);
+ lpn = llpn;
+ } else {
+ os_memcpy(ki.mi, body->osrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->okn);
+ lpn = olpn;
+ }
+
+ /* If the most recent distributed keys don't agree then someone is out
+ * of sync. Perhaps non key server hasn't processed the most recent
+ * distSAK yet and the key server is processing an old packet after it
+ * has done distSAK. Be lenient and don't return error in this
+ * particular case; otherwise, the key server will reset its MI and
+ * cause a traffic disruption which is really undesired for a simple
+ * timing issue.
+ */
+ if (!is_ki_equal(&sa_key->key_identifier, &ki)) {
+ wpa_printf(MSG_INFO,
+ "KaY: Distributed keys don't match - ignore SAK use");
+ return 0;
}
+ sa_key->next_pn = lpn;
- if (sa_key)
- sa_key->next_pn = lpn;
- found = FALSE;
- dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
- list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
- list) {
- if (sa_key && rxsa->pkey == sa_key) {
- found = TRUE;
+ /* The key server must check that all peers are using the most recent
+ * distributed key. Non key servers must check if the key server is
+ * transmitting.
+ */
+ if (participant->is_key_server) {
+ struct ieee802_1x_kay_peer *peer_iter;
+ bool all_receiving = true;
+
+ /* Distributed keys are equal from above comparison. */
+ peer->sak_used = true;
+
+ dl_list_for_each(peer_iter, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer_iter->sak_used) {
+ all_receiving = false;
break;
}
}
- if (found)
- break;
+ if (all_receiving) {
+ participant->to_dist_sak = false;
+ ieee802_1x_cp_set_allreceiving(kay->cp, true);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+ } else if (peer->is_key_server) {
+ if (body->ltx) {
+ ieee802_1x_cp_set_servertransmitting(kay->cp, true);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
}
- if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
- return -1;
+
+ /* If I'm key server, and detects peer member PN exhaustion, rekey.
+ * We only need to check the PN of the most recent distributed key. This
+ * could be the peer's "latest" or "old" key depending on its current
+ * state. If both "old" and "latest" keys are present then the "old" key
+ * has already been exhausted.
+ */
+ if (participant->is_key_server && lpn > kay->pn_exhaustion) {
+ participant->new_sak = true;
+ wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
}
+ /* Get the associated RX SAs of the keys for delay protection since both
+ * can be in use. Delay protect window (communicated via MKA) is tighter
+ * than SecY's current replay protect window, so tell SecY the new (and
+ * higher) lpn.
+ */
if (body->delay_protect) {
- secy_get_receive_lowest_pn(participant->kay, rxsa);
- if (lpn > rxsa->lowest_pn) {
- /* Delay protect window (communicated via MKA) is
- * tighter than SecY's current replay protect window,
- * so tell SecY the new (and higher) lpn. */
- rxsa->lowest_pn = lpn;
- secy_set_receive_lowest_pn(participant->kay, rxsa);
- wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
+ bool found = false;
+
+ dl_list_for_each(rxsc, &participant->rxsc_list,
+ struct receive_sc, list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list,
+ struct receive_sa, list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ if (found) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay,
+ rxsa);
+ wpa_printf(MSG_DEBUG,
+ "KaY: update dist LPN=0x%x", lpn);
+ }
}
- /* FIX: Delay protection for olpn not implemented.
- * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
- * (3 seconds) and delay protection does allow PN's within
- * a 2 seconds window, so olpn would be a lot of work for
- * just 1 second's worth of protection. */
+
+ /* FIX: Delay protection for the SA being replaced is not
+ * implemented. Note that this key will be active for at least
+ * MKA_SAK_RETIRE_TIME (3 seconds) but could be longer depending
+ * on how long it takes to get from RECEIVE to TRANSMITTING or
+ * if going via ABANDON. Delay protection does allow PNs within
+ * a 2 second window, so getting PN would be a lot of work for
+ * just 1 second's worth of protection.
+ */
}
return 0;
@@ -1533,7 +1570,7 @@ ieee802_1x_mka_decode_sak_use_body(
/**
* ieee802_1x_mka_dist_sak_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1626,8 +1663,8 @@ ieee802_1x_mka_encode_dist_sak_body(
*/
static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
{
- pkey->transmits = TRUE;
- pkey->receives = TRUE;
+ pkey->transmits = true;
+ pkey->receives = true;
os_get_time(&pkey->created_time);
pkey->next_pn = 1;
@@ -1693,21 +1730,21 @@ ieee802_1x_mka_decode_dist_sak_body(
}
if (body_len == 0) {
- kay->authenticated = TRUE;
- kay->secured = FALSE;
- kay->failed = FALSE;
- participant->advised_desired = FALSE;
+ kay->authenticated = true;
+ kay->secured = false;
+ kay->failed = false;
+ participant->advised_desired = false;
ieee802_1x_cp_connect_authenticated(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
wpa_printf(MSG_WARNING, "KaY: The Key server advise no MACsec");
- participant->to_use_sak = FALSE;
+ participant->to_use_sak = false;
return 0;
}
- participant->advised_desired = TRUE;
- kay->authenticated = FALSE;
- kay->secured = TRUE;
- kay->failed = FALSE;
+ participant->advised_desired = true;
+ kay->authenticated = false;
+ kay->secured = true;
+ kay->failed = false;
ieee802_1x_cp_connect_secure(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
@@ -1788,7 +1825,7 @@ ieee802_1x_mka_decode_dist_sak_body(
ieee802_1x_cp_sm_step(kay->cp);
kay->rcvd_keys++;
- participant->to_use_sak = TRUE;
+ participant->to_use_sak = true;
return 0;
}
@@ -1797,10 +1834,10 @@ ieee802_1x_mka_decode_dist_sak_body(
/**
* ieee802_1x_mka_icv_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_icv_body_present(struct ieee802_1x_mka_participant *participant)
{
- return TRUE;
+ return true;
}
@@ -1965,7 +2002,7 @@ struct mka_param_body_handler {
int (*body_rx)(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len);
int (*body_length)(struct ieee802_1x_mka_participant *participant);
- Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
+ bool (*body_present)(struct ieee802_1x_mka_participant *participant);
};
@@ -2192,7 +2229,7 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list)
- peer->sak_used = FALSE;
+ peer->sak_used = false;
kay->dist_kn++;
kay->dist_an++;
@@ -2232,13 +2269,13 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
struct ieee802_1x_kay_peer *peer;
struct ieee802_1x_kay_peer *key_server = NULL;
struct ieee802_1x_kay *kay = participant->kay;
- Boolean i_is_key_server;
+ bool i_is_key_server;
int priority_comparison;
if (participant->is_obliged_key_server) {
- participant->new_sak = TRUE;
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_electedself(kay->cp, TRUE);
+ participant->new_sak = true;
+ participant->to_dist_sak = false;
+ ieee802_1x_cp_set_electedself(kay->cp, true);
return 0;
}
@@ -2258,7 +2295,7 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
}
/* elect the key server between me and the above elected peer */
- i_is_key_server = FALSE;
+ i_is_key_server = false;
if (key_server && participant->can_be_key_server) {
struct ieee802_1x_kay_peer tmp;
@@ -2266,29 +2303,29 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
priority_comparison = compare_priorities(&tmp, key_server);
if (priority_comparison < 0) {
- i_is_key_server = TRUE;
+ i_is_key_server = true;
} else if (priority_comparison == 0) {
wpa_printf(MSG_WARNING,
"KaY: Cannot elect key server between me and peer, duplicate MAC detected");
key_server = NULL;
}
} else if (participant->can_be_key_server) {
- i_is_key_server = TRUE;
+ i_is_key_server = true;
}
if (i_is_key_server) {
- ieee802_1x_cp_set_electedself(kay->cp, TRUE);
+ ieee802_1x_cp_set_electedself(kay->cp, true);
if (!sci_equal(&kay->key_server_sci, &kay->actor_sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
- participant->is_key_server = TRUE;
- participant->principal = TRUE;
- participant->new_sak = TRUE;
+ participant->is_key_server = true;
+ participant->principal = true;
+ participant->new_sak = true;
wpa_printf(MSG_DEBUG, "KaY: I am elected as key server");
- participant->to_dist_sak = FALSE;
- participant->is_elected = TRUE;
+ participant->to_dist_sak = false;
+ participant->is_elected = true;
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
@@ -2297,23 +2334,23 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
wpa_printf(MSG_DEBUG,
"KaY: Peer %s was elected as the key server",
mi_txt(key_server->mi));
- ieee802_1x_cp_set_electedself(kay->cp, FALSE);
+ ieee802_1x_cp_set_electedself(kay->cp, false);
if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
- participant->is_key_server = FALSE;
- participant->principal = TRUE;
- participant->is_elected = TRUE;
+ participant->is_key_server = false;
+ participant->principal = true;
+ participant->is_elected = true;
os_memcpy(&kay->key_server_sci, &key_server->sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = key_server->key_server_priority;
} else {
- participant->principal = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
+ participant->principal = false;
+ participant->is_key_server = false;
+ participant->is_elected = false;
}
return 0;
@@ -2333,24 +2370,24 @@ ieee802_1x_kay_decide_macsec_use(
struct ieee802_1x_kay *kay = participant->kay;
struct ieee802_1x_kay_peer *peer;
enum macsec_cap less_capability;
- Boolean has_peer;
+ bool has_peer;
if (!participant->is_key_server)
return -1;
/* key server self is MACsec-desired and requesting MACsec */
if (!kay->macsec_desired) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
return -1;
}
if (kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
return -1;
}
less_capability = kay->macsec_capable;
/* at least one of peers is MACsec-desired and requesting MACsec */
- has_peer = FALSE;
+ has_peer = false;
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
if (!peer->macsec_desired)
@@ -2361,24 +2398,24 @@ ieee802_1x_kay_decide_macsec_use(
less_capability = (less_capability < peer->macsec_capability) ?
less_capability : peer->macsec_capability;
- has_peer = TRUE;
+ has_peer = true;
}
if (has_peer) {
- participant->advised_desired = TRUE;
+ participant->advised_desired = true;
participant->advised_capability = less_capability;
- kay->authenticated = FALSE;
- kay->secured = TRUE;
- kay->failed = FALSE;
+ kay->authenticated = false;
+ kay->secured = true;
+ kay->failed = false;
ieee802_1x_cp_connect_secure(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
} else {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
participant->advised_capability = MACSEC_CAP_NOT_IMPLEMENTED;
- participant->to_use_sak = FALSE;
- kay->authenticated = TRUE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ participant->to_use_sak = false;
+ kay->authenticated = true;
+ kay->secured = false;
+ kay->failed = false;
kay->ltx_kn = 0;
kay->ltx_an = 0;
kay->lrx_kn = 0;
@@ -2477,8 +2514,8 @@ ieee802_1x_participant_send_mkpdu(
l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
- kay->active = TRUE;
- participant->active = TRUE;
+ kay->active = true;
+ participant->active = true;
return 0;
}
@@ -2504,7 +2541,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
struct ieee802_1x_kay *kay;
struct ieee802_1x_kay_peer *peer, *pre_peer;
time_t now = time(NULL);
- Boolean lp_changed;
+ bool lp_changed;
struct receive_sc *rxsc, *pre_rxsc;
struct transmit_sa *txsa, *pre_txsa;
@@ -2528,7 +2565,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
}
}
- lp_changed = FALSE;
+ lp_changed = false;
dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
if (now > peer->expire) {
@@ -2546,25 +2583,25 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
}
dl_list_del(&peer->list);
os_free(peer);
- lp_changed = TRUE;
+ lp_changed = true;
}
}
if (lp_changed) {
if (dl_list_empty(&participant->live_peers)) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
participant->advised_capability =
MACSEC_CAP_NOT_IMPLEMENTED;
- participant->to_use_sak = FALSE;
- participant->ltx = FALSE;
- participant->lrx = FALSE;
- participant->otx = FALSE;
- participant->orx = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ participant->to_use_sak = false;
+ participant->ltx = false;
+ participant->lrx = false;
+ participant->otx = false;
+ participant->orx = false;
+ participant->is_key_server = false;
+ participant->is_elected = false;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = false;
kay->ltx_kn = 0;
kay->ltx_an = 0;
kay->lrx_kn = 0;
@@ -2601,9 +2638,9 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
if (participant->new_sak && participant->is_key_server) {
if (!ieee802_1x_kay_generate_new_sak(participant))
- participant->to_dist_sak = TRUE;
+ participant->to_dist_sak = true;
- participant->new_sak = FALSE;
+ participant->new_sak = false;
}
if (participant->retry_count < MAX_RETRY_CNT ||
@@ -2619,9 +2656,9 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
return;
delete_mka:
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = true;
ieee802_1x_kay_delete_mka(kay, &participant->ckn);
}
@@ -2635,8 +2672,8 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
{
struct transmit_sa *psa;
- key->tx_latest = TRUE;
- key->rx_latest = TRUE;
+ key->tx_latest = true;
+ key->rx_latest = true;
psa = os_zalloc(sizeof(*psa));
if (!psa) {
@@ -2646,9 +2683,9 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
if (key->confidentiality_offset >= CONFIDENTIALITY_OFFSET_0 &&
key->confidentiality_offset <= CONFIDENTIALITY_OFFSET_50)
- psa->confidentiality = TRUE;
+ psa->confidentiality = true;
else
- psa->confidentiality = FALSE;
+ psa->confidentiality = false;
psa->an = an;
ieee802_1x_kay_use_data_key(key);
@@ -2657,7 +2694,7 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
psa->sc = psc;
os_get_time(&psa->created_time);
- psa->in_use = FALSE;
+ psa->in_use = false;
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
@@ -2699,9 +2736,9 @@ ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci)
os_memcpy(&psc->sci, sci, sizeof(psc->sci));
os_get_time(&psc->created_time);
- psc->transmitting = FALSE;
- psc->encoding_sa = FALSE;
- psc->enciphering_sa = FALSE;
+ psc->transmitting = false;
+ psc->encoding_sa = false;
+ psc->enciphering_sa = false;
dl_list_init(&psc->sa_list);
wpa_printf(MSG_DEBUG, "KaY: Create transmit SC - SCI: %s",
@@ -2735,7 +2772,7 @@ ieee802_1x_kay_deinit_transmit_sc(
*/
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
- Boolean ltx, Boolean lrx)
+ bool ltx, bool lrx)
{
struct ieee802_1x_mka_participant *principal;
@@ -2770,7 +2807,7 @@ int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
*/
int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *oki,
- u8 oan, Boolean otx, Boolean orx)
+ u8 oan, bool otx, bool orx)
{
struct ieee802_1x_mka_participant *principal;
@@ -2846,13 +2883,13 @@ int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
latest_sak = NULL;
dl_list_for_each(sa_key, &principal->sak_list, struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, lki)) {
- sa_key->rx_latest = TRUE;
- sa_key->tx_latest = TRUE;
+ sa_key->rx_latest = true;
+ sa_key->tx_latest = true;
latest_sak = sa_key;
- principal->to_use_sak = TRUE;
+ principal->to_use_sak = true;
} else {
- sa_key->rx_latest = FALSE;
- sa_key->tx_latest = FALSE;
+ sa_key->rx_latest = false;
+ sa_key->tx_latest = false;
}
}
if (!latest_sak) {
@@ -2956,10 +2993,10 @@ int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
dl_list_for_each(txsa, &principal->txsc->sa_list, struct transmit_sa,
list) {
if (is_ki_equal(&txsa->pkey->key_identifier, lki)) {
- txsa->in_use = TRUE;
+ txsa->in_use = true;
secy_enable_transmit_sa(kay, txsa);
ieee802_1x_cp_set_usingtransmitas(
- principal->kay->cp, TRUE);
+ principal->kay->cp, true);
ieee802_1x_cp_sm_step(principal->kay->cp);
}
}
@@ -2986,10 +3023,10 @@ int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
{
if (is_ki_equal(&rxsa->pkey->key_identifier, lki)) {
- rxsa->in_use = TRUE;
+ rxsa->in_use = true;
secy_enable_receive_sa(kay, rxsa);
ieee802_1x_cp_set_usingreceivesas(
- principal->kay->cp, TRUE);
+ principal->kay->cp, true);
ieee802_1x_cp_sm_step(principal->kay->cp);
}
}
@@ -3171,10 +3208,10 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
u8 body_type;
int i;
const u8 *pos;
- Boolean handled[256];
- Boolean bad_sak_use = FALSE; /* Error detected while processing SAK Use
- * parameter set */
- Boolean i_in_peerlist, is_in_live_peer, is_in_potential_peer;
+ bool handled[256];
+ bool bad_sak_use = false; /* Error detected while processing SAK Use
+ * parameter set */
+ bool i_in_peerlist, is_in_live_peer, is_in_potential_peer;
wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
kay->if_name);
@@ -3231,9 +3268,9 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
* Each parameter set should be present only once.
*/
for (i = 0; i < 256; i++)
- handled[i] = FALSE;
+ handled[i] = false;
- handled[0] = TRUE;
+ handled[0] = true;
for (; left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
pos += body_len + MKA_HDR_LEN,
left_len -= body_len + MKA_HDR_LEN) {
@@ -3259,7 +3296,7 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
continue;
}
- handled[body_type] = TRUE;
+ handled[body_type] = true;
if (body_type < ARRAY_SIZE(mka_body_handler) &&
mka_body_handler[body_type].body_rx) {
if (mka_body_handler[body_type].body_rx
@@ -3280,7 +3317,7 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
* that it somehow processes DIST-SAK before
* SAK-USE, just ignore SAK-USE failures if
* DIST-SAK is also present in this MKPDU. */
- bad_sak_use = TRUE;
+ bad_sak_use = true;
}
} else {
wpa_printf(MSG_ERROR,
@@ -3349,9 +3386,9 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
* from 'potential_peers' to 'live_peers'. */
}
- kay->active = TRUE;
+ kay->active = true;
participant->retry_count = 0;
- participant->active = TRUE;
+ participant->active = true;
return 0;
}
@@ -3418,7 +3455,7 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- Boolean macsec_replay_protect, u32 macsec_replay_window,
+ bool macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3435,12 +3472,12 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
kay->ctx = ctx;
- kay->enable = TRUE;
- kay->active = FALSE;
+ kay->enable = true;
+ kay->active = false;
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = false;
kay->policy = policy;
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
@@ -3472,23 +3509,23 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
if (policy == DO_NOT_SECURE ||
kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
- kay->macsec_desired = FALSE;
- kay->macsec_protect = FALSE;
- kay->macsec_encrypt = FALSE;
+ kay->macsec_desired = false;
+ kay->macsec_protect = false;
+ kay->macsec_encrypt = false;
kay->macsec_validate = Disabled;
- kay->macsec_replay_protect = FALSE;
+ kay->macsec_replay_protect = false;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
kay->mka_hello_time = MKA_HELLO_TIME;
} else {
- kay->macsec_desired = TRUE;
- kay->macsec_protect = TRUE;
+ kay->macsec_desired = true;
+ kay->macsec_protect = true;
if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF &&
policy == SHOULD_ENCRYPT) {
- kay->macsec_encrypt = TRUE;
+ kay->macsec_encrypt = true;
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
} else { /* SHOULD_SECURE */
- kay->macsec_encrypt = FALSE;
+ kay->macsec_encrypt = false;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
}
kay->macsec_validate = Strict;
@@ -3586,7 +3623,7 @@ struct ieee802_1x_mka_participant *
ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
const struct mka_key_name *ckn,
const struct mka_key *cak, u32 life,
- enum mka_created_mode mode, Boolean is_authenticator)
+ enum mka_created_mode mode, bool is_authenticator)
{
struct ieee802_1x_mka_participant *participant;
unsigned int usecs;
@@ -3634,40 +3671,40 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
switch (mode) {
case EAP_EXCHANGE:
if (is_authenticator) {
- participant->is_obliged_key_server = TRUE;
- participant->can_be_key_server = TRUE;
- participant->is_key_server = TRUE;
- participant->principal = TRUE;
+ participant->is_obliged_key_server = true;
+ participant->can_be_key_server = true;
+ participant->is_key_server = true;
+ participant->principal = true;
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
- participant->is_elected = TRUE;
+ participant->is_elected = true;
} else {
- participant->is_obliged_key_server = FALSE;
- participant->can_be_key_server = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = TRUE;
+ participant->is_obliged_key_server = false;
+ participant->can_be_key_server = false;
+ participant->is_key_server = false;
+ participant->is_elected = true;
}
break;
default:
- participant->is_obliged_key_server = FALSE;
- participant->can_be_key_server = TRUE;
- participant->is_key_server = TRUE;
- participant->is_elected = FALSE;
+ participant->is_obliged_key_server = false;
+ participant->can_be_key_server = true;
+ participant->is_key_server = true;
+ participant->is_elected = false;
break;
}
- participant->cached = FALSE;
+ participant->cached = false;
- participant->active = FALSE;
- participant->participant = FALSE;
- participant->retain = FALSE;
+ participant->active = false;
+ participant->participant = false;
+ participant->retain = false;
participant->activate = DEFAULT;
if (participant->is_key_server)
- participant->principal = TRUE;
+ participant->principal = true;
dl_list_init(&participant->live_peers);
dl_list_init(&participant->potential_peers);
@@ -3680,13 +3717,13 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
mi_txt(participant->mi));
- participant->lrx = FALSE;
- participant->ltx = FALSE;
- participant->orx = FALSE;
- participant->otx = FALSE;
- participant->to_dist_sak = FALSE;
- participant->to_use_sak = FALSE;
- participant->new_sak = FALSE;
+ participant->lrx = false;
+ participant->ltx = false;
+ participant->orx = false;
+ participant->otx = false;
+ participant->to_dist_sak = false;
+ participant->to_use_sak = false;
+ participant->new_sak = false;
dl_list_init(&participant->sak_list);
participant->new_key = NULL;
dl_list_init(&participant->rxsc_list);
@@ -3819,8 +3856,7 @@ ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
* ieee802_1x_kay_mka_participate -
*/
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
- struct mka_key_name *ckn,
- Boolean status)
+ struct mka_key_name *ckn, bool status)
{
struct ieee802_1x_mka_participant *participant;
@@ -3850,7 +3886,7 @@ ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
if (!participant)
return -1;
- participant->new_sak = TRUE;
+ participant->new_sak = true;
wpa_printf(MSG_DEBUG, "KaY: new SAK signal");
return 0;
@@ -3879,7 +3915,7 @@ ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
return -2;
if (cs_index == 0)
- kay->macsec_desired = FALSE;
+ kay->macsec_desired = false;
kay->macsec_csindex = cs_index;
kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
@@ -3893,7 +3929,7 @@ ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
participant = ieee802_1x_kay_get_principal_participant(kay);
if (participant) {
wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
- participant->new_sak = TRUE;
+ participant->new_sak = true;
}
return 0;
@@ -4007,7 +4043,7 @@ int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
}
-static const char * true_false(Boolean val)
+static const char * true_false(bool val)
{
return val ? "true" : "false";
}
@@ -4030,7 +4066,7 @@ static const char * activate_control_txt(enum activate_ctrl activate)
}
-static char * mka_mib_peer(struct dl_list *peers, Boolean live, char *buf,
+static char * mka_mib_peer(struct dl_list *peers, bool live, char *buf,
char *end)
{
char *pos = buf;
@@ -4097,8 +4133,8 @@ int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
pos2 += res;
pos = pos2;
- pos = mka_mib_peer(&p->live_peers, TRUE, pos, end);
- pos = mka_mib_peer(&p->potential_peers, FALSE, pos, end);
+ pos = mka_mib_peer(&p->live_peers, true, pos, end);
+ pos = mka_mib_peer(&p->potential_peers, false, pos, end);
}
return pos - buf;
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.h b/contrib/wpa/src/pae/ieee802_1x_kay.h
index 3367d3aaa8c1..1d3c2acb72f4 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay.h
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.h
@@ -62,14 +62,14 @@ struct data_key {
struct ieee802_1x_mka_ki key_identifier;
enum confidentiality_offset confidentiality_offset;
u8 an;
- Boolean transmits;
- Boolean receives;
+ bool transmits;
+ bool receives;
struct os_time created_time;
u32 next_pn;
/* not defined data */
- Boolean rx_latest;
- Boolean tx_latest;
+ bool rx_latest;
+ bool tx_latest;
int user;
@@ -79,7 +79,7 @@ struct data_key {
/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
struct transmit_sc {
struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean transmitting; /* bool transmitting (read only) */
+ bool transmitting; /* bool transmitting (read only) */
struct os_time created_time; /* Time createdTime */
@@ -93,14 +93,14 @@ struct transmit_sc {
/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
struct transmit_sa {
- Boolean in_use; /* bool inUse (read only) */
+ bool in_use; /* bool inUse (read only) */
u32 next_pn; /* PN nextPN (read only) */
struct os_time created_time; /* Time createdTime */
- Boolean enable_transmit; /* bool EnableTransmit */
+ bool enable_transmit; /* bool EnableTransmit */
u8 an;
- Boolean confidentiality;
+ bool confidentiality;
struct data_key *pkey;
struct transmit_sc *sc;
@@ -110,7 +110,7 @@ struct transmit_sa {
/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
struct receive_sc {
struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean receiving; /* bool receiving (read only) */
+ bool receiving; /* bool receiving (read only) */
struct os_time created_time; /* Time createdTime */
@@ -120,8 +120,8 @@ struct receive_sc {
/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
struct receive_sa {
- Boolean enable_receive; /* bool enableReceive */
- Boolean in_use; /* bool inUse (read only) */
+ bool enable_receive; /* bool enableReceive */
+ bool in_use; /* bool inUse (read only) */
u32 next_pn; /* PN nextPN (read only) */
u32 lowest_pn; /* PN lowestPN (read only) */
@@ -142,11 +142,11 @@ struct ieee802_1x_kay_ctx {
int (*macsec_init)(void *ctx, struct macsec_init_params *params);
int (*macsec_deinit)(void *ctx);
int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
- int (*enable_protect_frames)(void *ctx, Boolean enabled);
- int (*enable_encrypt)(void *ctx, Boolean enabled);
- int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
+ int (*enable_protect_frames)(void *ctx, bool enabled);
+ int (*enable_encrypt)(void *ctx, bool enabled);
+ int (*set_replay_protect)(void *ctx, bool enabled, u32 window);
int (*set_current_cipher_suite)(void *ctx, u64 cs);
- int (*enable_controlled_port)(void *ctx, Boolean enabled);
+ int (*enable_controlled_port)(void *ctx, bool enabled);
int (*get_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
int (*get_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
int (*set_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
@@ -169,12 +169,12 @@ struct ieee802_1x_kay_ctx {
};
struct ieee802_1x_kay {
- Boolean enable;
- Boolean active;
+ bool enable;
+ bool active;
- Boolean authenticated;
- Boolean secured;
- Boolean failed;
+ bool authenticated;
+ bool secured;
+ bool failed;
struct ieee802_1x_mka_sci actor_sci;
u8 actor_priority;
@@ -182,10 +182,10 @@ struct ieee802_1x_kay {
u8 key_server_priority;
enum macsec_cap macsec_capable;
- Boolean macsec_desired;
- Boolean macsec_protect;
- Boolean macsec_encrypt;
- Boolean macsec_replay_protect;
+ bool macsec_desired;
+ bool macsec_protect;
+ bool macsec_encrypt;
+ bool macsec_replay_protect;
u32 macsec_replay_window;
enum validate_frames macsec_validate;
enum confidentiality_offset macsec_confidentiality;
@@ -203,8 +203,8 @@ struct ieee802_1x_kay {
/* not defined in IEEE802.1X */
struct ieee802_1x_kay_ctx *ctx;
- Boolean is_key_server;
- Boolean is_obliged_key_server;
+ bool is_key_server;
+ bool is_obliged_key_server;
char if_name[IFNAMSIZ];
unsigned int macsec_csindex; /* MACsec cipher suite table index */
@@ -219,9 +219,9 @@ struct ieee802_1x_kay {
u8 algo_agility[4];
u32 pn_exhaustion;
- Boolean port_enable;
- Boolean rx_enable;
- Boolean tx_enable;
+ bool port_enable;
+ bool rx_enable;
+ bool tx_enable;
struct dl_list participant_list;
enum macsec_policy policy;
@@ -239,7 +239,7 @@ u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci);
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- Boolean macsec_replay_protect, u32 macsec_replay_window,
+ bool macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
@@ -248,22 +248,22 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
const struct mka_key_name *ckn,
const struct mka_key *cak,
u32 life, enum mka_created_mode mode,
- Boolean is_authenticator);
+ bool is_authenticator);
void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
struct mka_key_name *ckn);
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
struct mka_key_name *ckn,
- Boolean status);
+ bool status);
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
unsigned int cs_index);
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
- Boolean ltx, Boolean lrx);
+ bool ltx, bool lrx);
int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *oki,
- u8 oan, Boolean otx, Boolean orx);
+ u8 oan, bool otx, bool orx);
int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki);
int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay_i.h b/contrib/wpa/src/pae/ieee802_1x_kay_i.h
index f9cd3f41b093..7a041692a5d5 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay_i.h
+++ b/contrib/wpa/src/pae/ieee802_1x_kay_i.h
@@ -46,11 +46,11 @@ struct ieee802_1x_kay_peer {
u8 mi[MI_LEN];
u32 mn;
time_t expire;
- Boolean is_key_server;
+ bool is_key_server;
u8 key_server_priority;
- Boolean macsec_desired;
+ bool macsec_desired;
enum macsec_cap macsec_capability;
- Boolean sak_used;
+ bool sak_used;
int missing_sak_use_count;
struct dl_list list;
};
@@ -87,18 +87,18 @@ struct ieee802_1x_mka_participant {
/* used for active and potential participant */
struct mka_key_name ckn;
struct mka_key cak;
- Boolean cached;
+ bool cached;
/* used by management to monitor and control activation */
- Boolean active;
- Boolean participant;
- Boolean retain;
+ bool active;
+ bool participant;
+ bool retain;
enum mka_created_mode mode;
enum activate_ctrl { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
/* used for active participant */
- Boolean principal;
+ bool principal;
struct dl_list live_peers;
struct dl_list potential_peers;
@@ -110,18 +110,18 @@ struct ieee802_1x_mka_participant {
struct ieee802_1x_mka_ki lki;
u8 lan;
- Boolean ltx;
- Boolean lrx;
+ bool ltx;
+ bool lrx;
struct ieee802_1x_mka_ki oki;
u8 oan;
- Boolean otx;
- Boolean orx;
+ bool otx;
+ bool orx;
- Boolean is_key_server;
- Boolean is_obliged_key_server;
- Boolean can_be_key_server;
- Boolean is_elected;
+ bool is_key_server;
+ bool is_obliged_key_server;
+ bool can_be_key_server;
+ bool is_elected;
struct dl_list sak_list;
struct dl_list rxsc_list;
@@ -137,11 +137,11 @@ struct ieee802_1x_mka_participant {
time_t cak_life;
time_t mka_life;
- Boolean to_dist_sak;
- Boolean to_use_sak;
- Boolean new_sak;
+ bool to_dist_sak;
+ bool to_use_sak;
+ bool new_sak;
- Boolean advised_desired;
+ bool advised_desired;
enum macsec_cap advised_capability;
struct data_key *new_key;
diff --git a/contrib/wpa/src/pae/ieee802_1x_secy_ops.c b/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
index 84ee42b05896..0f36e6b536b1 100644
--- a/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
@@ -25,7 +25,7 @@ int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
}
-int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -45,7 +45,7 @@ int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean enabled)
}
-int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -65,7 +65,7 @@ int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
}
-int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
+int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool enabled, u32 win)
{
struct ieee802_1x_kay_ctx *ops;
@@ -113,7 +113,7 @@ int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
}
-int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -333,7 +333,7 @@ int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
return -1;
}
- rxsa->enable_receive = TRUE;
+ rxsa->enable_receive = true;
return ops->enable_receive_sa(ops->ctx, rxsa);
}
@@ -355,7 +355,7 @@ int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
return -1;
}
- rxsa->enable_receive = FALSE;
+ rxsa->enable_receive = false;
return ops->disable_receive_sa(ops->ctx, rxsa);
}
@@ -462,7 +462,7 @@ int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
return -1;
}
- txsa->enable_transmit = TRUE;
+ txsa->enable_transmit = true;
return ops->enable_transmit_sa(ops->ctx, txsa);
}
@@ -485,7 +485,7 @@ int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
return -1;
}
- txsa->enable_transmit = FALSE;
+ txsa->enable_transmit = false;
return ops->disable_transmit_sa(ops->ctx, txsa);
}
@@ -509,9 +509,9 @@ int secy_init_macsec(struct ieee802_1x_kay *kay)
return -1;
}
- params.use_es = FALSE;
- params.use_scb = FALSE;
- params.always_include_sci = TRUE;
+ params.use_es = false;
+ params.use_scb = false;
+ params.always_include_sci = true;
ret = ops->macsec_init(ops->ctx, &params);
diff --git a/contrib/wpa/src/pae/ieee802_1x_secy_ops.h b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
index 2d112ba7c5d5..18c06f665aa3 100644
--- a/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
@@ -20,13 +20,13 @@ int secy_deinit_macsec(struct ieee802_1x_kay *kay);
/****** CP -> SecY ******/
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
enum validate_frames vf);
-int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
-int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled);
-int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
+int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool flag);
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled);
+int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool flag, u32 win);
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
enum confidentiality_offset co);
-int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean flag);
+int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, bool flag);
/****** KaY -> SecY *******/
int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap);
diff --git a/contrib/wpa/src/radius/Makefile b/contrib/wpa/src/radius/Makefile
new file mode 100644
index 000000000000..8cfb33d35f9f
--- /dev/null
+++ b/contrib/wpa/src/radius/Makefile
@@ -0,0 +1,9 @@
+CFLAGS += -DCONFIG_IPV6
+
+LIB_OBJS= \
+ radius.o \
+ radius_client.o \
+ radius_das.o \
+ radius_server.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/radius/radius.c b/contrib/wpa/src/radius/radius.c
index 07240ea2243d..be16e27b9d7c 100644
--- a/contrib/wpa/src/radius/radius.c
+++ b/contrib/wpa/src/radius/radius.c
@@ -609,7 +609,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
{
if (msg->attr_used >= msg->attr_size) {
size_t *nattr_pos;
- int nlen = msg->attr_size * 2;
+ size_t nlen = msg->attr_size * 2;
nattr_pos = os_realloc_array(msg->attr_pos, nlen,
sizeof(*msg->attr_pos));
diff --git a/contrib/wpa/src/radius/radius.h b/contrib/wpa/src/radius/radius.h
index 630c0f9d0bc5..fb814818072a 100644
--- a/contrib/wpa/src/radius/radius.h
+++ b/contrib/wpa/src/radius/radius.h
@@ -225,6 +225,9 @@ struct radius_msg;
/* Default size to be allocated for attribute array */
#define RADIUS_DEFAULT_ATTR_COUNT 16
+/* Maximum message length for incoming RADIUS messages, as stated in RFC 2865
+ * Section 3 ("Packet Format").*/
+#define RADIUS_MAX_MSG_LEN 4096
/* MAC address ASCII format for IEEE 802.1X use
* (draft-congdon-radius-8021x-20.txt) */
diff --git a/contrib/wpa/src/radius/radius_client.c b/contrib/wpa/src/radius/radius_client.c
index a3db4048c4a7..15902f0c9e29 100644
--- a/contrib/wpa/src/radius/radius_client.c
+++ b/contrib/wpa/src/radius/radius_client.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <net/if.h>
#include "common.h"
#include "radius.h"
@@ -457,7 +458,7 @@ static int radius_client_retransmit(struct radius_client_data *radius,
}
/* retransmit; remove entry if too many attempts */
- if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ if (entry->accu_attempts >= RADIUS_CLIENT_MAX_FAILOVER *
RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
wpa_printf(MSG_INFO,
"RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
@@ -507,7 +508,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
if (now.sec >= entry->next_try) {
s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
radius->acct_sock;
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+ if (entry->attempts >= RADIUS_CLIENT_NUM_FAILOVER ||
(s < 0 && entry->attempts > 0)) {
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM)
@@ -814,9 +815,14 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct radius_client_data *radius = eloop_ctx;
struct hostapd_radius_servers *conf = radius->conf;
+#if defined(__clang_major__) && __clang_major__ >= 11
+#pragma GCC diagnostic ignored "-Wvoid-pointer-to-enum-cast"
+#endif
RadiusType msg_type = (RadiusType) sock_ctx;
int len, roundtrip;
- unsigned char buf[3000];
+ unsigned char buf[RADIUS_MAX_MSG_LEN];
+ struct msghdr msghdr = {0};
+ struct iovec iov;
struct radius_msg *msg;
struct radius_hdr *hdr;
struct radius_rx_handler *handlers;
@@ -836,15 +842,22 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
rconf = conf->auth_server;
}
- len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
+ iov.iov_base = buf;
+ iov.iov_len = RADIUS_MAX_MSG_LEN;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+ len = recvmsg(sock, &msghdr, MSG_DONTWAIT);
if (len < 0) {
- wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
+ wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
return;
}
+
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
"server", len);
- if (len == sizeof(buf)) {
+
+ if (msghdr.msg_flags & MSG_TRUNC) {
wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
return;
}
@@ -1116,7 +1129,7 @@ radius_change_server(struct radius_client_data *radius,
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 1;
+ entry->attempts = 0;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
@@ -1159,6 +1172,29 @@ radius_change_server(struct radius_client_data *radius,
return -1;
}
+ /* Force a reconnect by disconnecting the socket first */
+ if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
+ sizeof(disconnect_addr)) < 0)
+ wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
+
+#ifdef __linux__
+ if (conf->force_client_dev && conf->force_client_dev[0]) {
+ if (setsockopt(sel_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ conf->force_client_dev,
+ os_strlen(conf->force_client_dev)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "RADIUS: setsockopt[SO_BINDTODEVICE]: %s",
+ strerror(errno));
+ /* Probably not a critical error; continue on and hope
+ * for the best. */
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Bound client socket to device: %s",
+ conf->force_client_dev);
+ }
+ }
+#endif /* __linux__ */
+
if (conf->force_client_addr) {
switch (conf->client_addr.af) {
case AF_INET:
@@ -1191,11 +1227,6 @@ radius_change_server(struct radius_client_data *radius,
}
}
- /* Force a reconnect by disconnecting the socket first */
- if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
- sizeof(disconnect_addr)) < 0)
- wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
-
if (connect(sel_sock, addr, addrlen) < 0) {
wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
return -1;
diff --git a/contrib/wpa/src/radius/radius_client.h b/contrib/wpa/src/radius/radius_client.h
index 8ca0874db498..687cd81aed91 100644
--- a/contrib/wpa/src/radius/radius_client.h
+++ b/contrib/wpa/src/radius/radius_client.h
@@ -174,6 +174,11 @@ struct hostapd_radius_servers {
* force_client_addr - Whether to force client (local) address
*/
int force_client_addr;
+
+ /**
+ * force_client_dev - Bind the socket to a specified interface, if set
+ */
+ char *force_client_dev;
};
diff --git a/contrib/wpa/src/radius/radius_server.c b/contrib/wpa/src/radius/radius_server.c
index 70efd11b49d9..e02c21540f5d 100644
--- a/contrib/wpa/src/radius/radius_server.c
+++ b/contrib/wpa/src/radius/radius_server.c
@@ -35,11 +35,6 @@
*/
#define RADIUS_MAX_SESSION 1000
-/**
- * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
- */
-#define RADIUS_MAX_MSG_LEN 3000
-
static const struct eapol_callbacks radius_server_eapol_cb;
struct radius_client;
@@ -161,145 +156,10 @@ struct radius_server_data {
*/
int num_sess;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- int eap_sim_id;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - The D-H group assigned for EAP-pwd
- *
- * If EAP-pwd is not used it can be set to zero.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
struct dl_list erp_keys; /* struct eap_server_erp_key */
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -351,11 +211,6 @@ struct radius_server_data {
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -369,6 +224,8 @@ struct radius_server_data {
#ifdef CONFIG_SQLITE
sqlite3 *db;
#endif /* CONFIG_SQLITE */
+
+ const struct eap_config *eap_cfg;
};
@@ -619,7 +476,7 @@ radius_server_new_session(struct radius_server_data *data,
#ifdef CONFIG_TESTING_OPTIONS
static void radius_server_testing_options_tls(struct radius_session *sess,
const char *tls,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
int test = atoi(tls);
@@ -664,7 +521,7 @@ static void radius_server_testing_options_tls(struct radius_session *sess,
#endif /* CONFIG_TESTING_OPTIONS */
static void radius_server_testing_options(struct radius_session *sess,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
#ifdef CONFIG_TESTING_OPTIONS
const char *pos;
@@ -707,7 +564,7 @@ radius_server_get_new_session(struct radius_server_data *data,
size_t user_len, id_len;
int res;
struct radius_session *sess;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -725,7 +582,7 @@ radius_server_get_new_session(struct radius_server_data *data,
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
#ifdef CONFIG_ERP
- if (res != 0 && data->erp) {
+ if (res != 0 && data->eap_cfg->erp) {
char *username;
username = os_zalloc(user_len + 1);
@@ -784,34 +641,10 @@ radius_server_get_new_session(struct radius_server_data *data,
srv_log(sess, "New session created");
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.ssl_ctx = data->ssl_ctx;
- eap_conf.msg_ctx = data->msg_ctx;
- eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
- eap_conf.backend_auth = TRUE;
- eap_conf.eap_server = 1;
- eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = data->eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
- eap_conf.eap_fast_prov = data->eap_fast_prov;
- eap_conf.pac_key_lifetime = data->pac_key_lifetime;
- eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
- eap_conf.eap_teap_auth = data->eap_teap_auth;
- eap_conf.eap_teap_pac_no_inner = data->eap_teap_pac_no_inner;
- eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
- eap_conf.eap_sim_id = data->eap_sim_id;
- eap_conf.tnc = data->tnc;
- eap_conf.wps = data->wps;
- eap_conf.pwd_group = data->pwd_group;
- eap_conf.server_id = (const u8 *) data->server_id;
- eap_conf.server_id_len = os_strlen(data->server_id);
- eap_conf.erp = data->erp;
- eap_conf.tls_session_lifetime = data->tls_session_lifetime;
- eap_conf.tls_flags = data->tls_flags;
- radius_server_testing_options(sess, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ radius_server_testing_options(sess, &eap_sess);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
- &eap_conf);
+ data->eap_cfg, &eap_sess);
if (sess->eap == NULL) {
RADIUS_DEBUG("Failed to initialize EAP state machine for the "
"new session");
@@ -819,8 +652,8 @@ radius_server_get_new_session(struct radius_server_data *data,
return NULL;
}
sess->eap_if = eap_get_interface(sess->eap);
- sess->eap_if->eapRestart = TRUE;
- sess->eap_if->portEnabled = TRUE;
+ sess->eap_if->eapRestart = true;
+ sess->eap_if->portEnabled = true;
RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
@@ -1071,13 +904,13 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
if (sess->eap_if->eapFail) {
- sess->eap_if->eapFail = FALSE;
+ sess->eap_if->eapFail = false;
code = RADIUS_CODE_ACCESS_REJECT;
} else if (sess->eap_if->eapSuccess) {
- sess->eap_if->eapSuccess = FALSE;
+ sess->eap_if->eapSuccess = false;
code = RADIUS_CODE_ACCESS_ACCEPT;
} else {
- sess->eap_if->eapReq = FALSE;
+ sess->eap_if->eapReq = false;
code = RADIUS_CODE_ACCESS_CHALLENGE;
}
@@ -1605,7 +1438,7 @@ static int radius_server_request(struct radius_server_data *data,
wpabuf_free(sess->eap_if->eapRespData);
sess->eap_if->eapRespData = eap;
- sess->eap_if->eapResp = TRUE;
+ sess->eap_if->eapResp = true;
eap_server_sm_step(sess->eap);
if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
@@ -2363,76 +2196,52 @@ radius_server_init(struct radius_server_conf *conf)
if (data == NULL)
return NULL;
+ data->eap_cfg = conf->eap_cfg;
data->auth_sock = -1;
data->acct_sock = -1;
dl_list_init(&data->erp_keys);
os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
- data->eap_sim_db_priv = conf->eap_sim_db_priv;
- data->ssl_ctx = conf->ssl_ctx;
- data->msg_ctx = conf->msg_ctx;
+ conf->eap_cfg->backend_auth = true;
+ conf->eap_cfg->eap_server = 1;
data->ipv6 = conf->ipv6;
- if (conf->pac_opaque_encr_key) {
- data->pac_opaque_encr_key = os_malloc(16);
- if (data->pac_opaque_encr_key) {
- os_memcpy(data->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (data->eap_fast_a_id) {
- os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- data->eap_fast_prov = conf->eap_fast_prov;
- data->pac_key_lifetime = conf->pac_key_lifetime;
- data->pac_key_refresh_time = conf->pac_key_refresh_time;
- data->eap_teap_auth = conf->eap_teap_auth;
- data->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
data->get_eap_user = conf->get_eap_user;
- data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- data->eap_sim_id = conf->eap_sim_id;
- data->tnc = conf->tnc;
- data->wps = conf->wps;
- data->pwd_group = conf->pwd_group;
- data->server_id = conf->server_id;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
- if (data->eap_req_id_text) {
- os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
- conf->eap_req_id_text_len);
- data->eap_req_id_text_len = conf->eap_req_id_text_len;
- }
+ if (!data->eap_req_id_text)
+ goto fail;
+ os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+ conf->eap_req_id_text_len);
+ data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
- data->erp = conf->erp;
data->erp_domain = conf->erp_domain;
- data->tls_session_lifetime = conf->tls_session_lifetime;
- data->tls_flags = conf->tls_flags;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
os_strdup(conf->subscr_remediation_url);
+ if (!data->subscr_remediation_url)
+ goto fail;
}
data->subscr_remediation_method = conf->subscr_remediation_method;
- if (conf->hs20_sim_provisioning_url)
+ if (conf->hs20_sim_provisioning_url) {
data->hs20_sim_provisioning_url =
os_strdup(conf->hs20_sim_provisioning_url);
+ if (!data->hs20_sim_provisioning_url)
+ goto fail;
+ }
- if (conf->t_c_server_url)
+ if (conf->t_c_server_url) {
data->t_c_server_url = os_strdup(conf->t_c_server_url);
+ if (!data->t_c_server_url)
+ goto fail;
+ }
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
if (sqlite3_open(conf->sqlite_file, &data->db)) {
RADIUS_ERROR("Could not open SQLite file '%s'",
conf->sqlite_file);
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
}
#endif /* CONFIG_SQLITE */
@@ -2446,8 +2255,7 @@ radius_server_init(struct radius_server_conf *conf)
conf->ipv6);
if (data->clients == NULL) {
wpa_printf(MSG_ERROR, "No RADIUS clients configured");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
#ifdef CONFIG_IPV6
@@ -2458,14 +2266,12 @@ radius_server_init(struct radius_server_conf *conf)
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->auth_sock,
radius_server_receive_auth,
data, NULL)) {
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (conf->acct_port) {
@@ -2478,20 +2284,20 @@ radius_server_init(struct radius_server_conf *conf)
data->acct_sock = radius_server_open_socket(conf->acct_port);
if (data->acct_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->acct_sock,
radius_server_receive_acct,
- data, NULL)) {
- radius_server_deinit(data);
- return NULL;
- }
+ data, NULL))
+ goto fail;
} else {
data->acct_sock = -1;
}
return data;
+fail:
+ radius_server_deinit(data);
+ return NULL;
}
@@ -2534,9 +2340,6 @@ void radius_server_deinit(struct radius_server_data *data)
radius_server_free_clients(data, data->clients);
- os_free(data->pac_opaque_encr_key);
- os_free(data->eap_fast_a_id);
- os_free(data->eap_fast_a_id_info);
os_free(data->eap_req_id_text);
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
diff --git a/contrib/wpa/src/radius/radius_server.h b/contrib/wpa/src/radius/radius_server.h
index 54896946eca9..43192e58596c 100644
--- a/contrib/wpa/src/radius/radius_server.h
+++ b/contrib/wpa/src/radius/radius_server.h
@@ -51,143 +51,8 @@ struct radius_server_conf {
*/
void *conf_ctx;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- int eap_teap_auth;
- int eap_teap_pac_no_inner;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- int eap_sim_id;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - EAP-pwd D-H group
- *
- * This is used to select which D-H group to use with EAP-pwd.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -227,11 +92,6 @@ struct radius_server_conf {
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -241,6 +101,8 @@ struct radius_server_conf {
char *hs20_sim_provisioning_url;
char *t_c_server_url;
+
+ struct eap_config *eap_cfg;
};
diff --git a/contrib/wpa/src/rsn_supp/Makefile b/contrib/wpa/src/rsn_supp/Makefile
new file mode 100644
index 000000000000..d14d736c1db6
--- /dev/null
+++ b/contrib/wpa/src/rsn_supp/Makefile
@@ -0,0 +1,14 @@
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_TDLS
+CFLAGS += -DCONFIG_WNM
+CFLAGS += -DIEEE8021X_EAPOL
+
+LIB_OBJS= \
+ pmksa_cache.o \
+ wpa_ft.o \
+ tdls.o \
+ preauth.o \
+ wpa.o \
+ wpa_ie.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.c b/contrib/wpa/src/rsn_supp/pmksa_cache.c
index d720f7b81144..97a01a2f81e8 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.c
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.c
@@ -212,7 +212,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
"that was based on the old PMK");
if (!pos->opportunistic)
pmksa_cache_flush(pmksa, entry->network_ctx,
- pos->pmk, pos->pmk_len);
+ pos->pmk, pos->pmk_len,
+ false);
pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
@@ -267,7 +268,10 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
entry->network_ctx, entry->akmp);
wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
- entry->pmk, entry->pmk_len);
+ entry->pmk, entry->pmk_len,
+ pmksa->sm->dot11RSNAConfigPMKLifetime,
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold,
+ entry->akmp);
return entry;
}
@@ -277,11 +281,13 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
- * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk: PMK to match for or %NULL to match all PMKs
* @pmk_len: PMK length
+ * @external_only: Flush only PMKSA cache entries configured by external
+ * applications
*/
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len, bool external_only)
{
struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
int removed = 0;
@@ -292,7 +298,8 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
network_ctx == NULL) &&
(pmk == NULL ||
(pmk_len == entry->pmk_len &&
- os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
+ os_memcmp(pmk, entry->pmk, pmk_len) == 0)) &&
+ (!external_only || entry->external)) {
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
"for " MACSTR, MAC2STR(entry->aa));
if (prev)
@@ -371,9 +378,13 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *new_entry;
os_time_t old_expiration = old_entry->expiration;
+ const u8 *pmkid = NULL;
+ if (wpa_key_mgmt_sae(old_entry->akmp) ||
+ wpa_key_mgmt_fils(old_entry->akmp))
+ pmkid = old_entry->pmkid;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
- NULL, NULL, 0,
+ pmkid, NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp,
old_entry->fils_cache_id_set ?
@@ -413,6 +424,20 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
while (entry) {
if (entry->network_ctx == network_ctx &&
(!akmp || entry->akmp == akmp)) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(entry->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ entry->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not clone PMKSA cache entry for "
+ MACSTR
+ " since its reauth threshold has passed",
+ MAC2STR(entry->aa));
+ entry = entry->next;
+ continue;
+ }
+
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -466,6 +491,9 @@ void pmksa_cache_clear_current(struct wpa_sm *sm)
{
if (sm == NULL)
return;
+ if (sm->cur_pmksa)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Clear current PMKSA entry selection");
sm->cur_pmksa = NULL;
}
@@ -516,6 +544,20 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
network_ctx,
fils_cache_id);
if (sm->cur_pmksa) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ sm->cur_pmksa->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not allow PMKSA cache entry for "
+ MACSTR
+ " to be used for SAE since its reauth threshold has passed",
+ MAC2STR(sm->cur_pmksa->aa));
+ sm->cur_pmksa = NULL;
+ return -1;
+ }
+
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
return 0;
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.h b/contrib/wpa/src/rsn_supp/pmksa_cache.h
index 6c49fa9248fb..ae7bc13fa118 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.h
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.h
@@ -28,6 +28,7 @@ struct rsn_pmksa_cache_entry {
*/
u8 fils_cache_id[2];
unsigned int fils_cache_id_set:1;
+ unsigned int dpp_pfs:1;
os_time_t reauth_time;
@@ -42,6 +43,7 @@ struct rsn_pmksa_cache_entry {
*/
void *network_ctx;
int opportunistic;
+ bool external;
};
struct rsn_pmksa_cache;
@@ -83,7 +85,7 @@ struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa, int akmp);
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
- const u8 *pmk, size_t pmk_len);
+ const u8 *pmk, size_t pmk_len, bool external_only);
#else /* IEEE8021X_EAPOL */
@@ -156,7 +158,8 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
void *network_ctx,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ bool external_only)
{
}
diff --git a/contrib/wpa/src/rsn_supp/preauth.c b/contrib/wpa/src/rsn_supp/preauth.c
index d0c43f464e27..1a38bf6bcbfa 100644
--- a/contrib/wpa/src/rsn_supp/preauth.c
+++ b/contrib/wpa/src/rsn_supp/preauth.c
@@ -49,6 +49,15 @@ void pmksa_candidate_free(struct wpa_sm *sm)
}
+static int rsn_preauth_key_mgmt(int akmp)
+{
+ return !!(akmp & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -243,9 +252,9 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
- eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portValid(sm->preauth_eapol, true);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portEnabled(sm->preauth_eapol, true);
eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
rsn_preauth_timeout, sm, NULL);
@@ -311,10 +320,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
if (sm->preauth_eapol ||
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
- (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
+ !rsn_preauth_key_mgmt(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -343,7 +349,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len);
+ NULL, p->pmk, p->pmk_len, 0, 0,
+ p->akmp);
}
dl_list_del(&candidate->list);
@@ -488,6 +495,9 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
+ if (!rsn_preauth_key_mgmt(ie.key_mgmt))
+ return;
+
/* Give less priority to candidates found from normal scan results. */
pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
ie.capabilities & WPA_CAPABILITY_PREAUTH);
diff --git a/contrib/wpa/src/rsn_supp/tdls.c b/contrib/wpa/src/rsn_supp/tdls.c
index 704c95e68616..411cbf46a40d 100644
--- a/contrib/wpa/src/rsn_supp/tdls.c
+++ b/contrib/wpa/src/rsn_supp/tdls.c
@@ -136,6 +136,8 @@ struct wpa_tdls_peer {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ struct ieee80211_he_capabilities *he_capabilities;
+ size_t he_capab_len;
u8 qos_info;
@@ -178,7 +180,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
- 0, 0, NULL, 0, NULL, 0) < 0) {
+ 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
"the driver");
return -1;
@@ -227,8 +229,9 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
MAC2STR(peer->addr));
- if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
- rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+ if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc),
+ peer->tpk.tk, key_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
"driver");
return -1;
@@ -702,6 +705,8 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->ht_capabilities = NULL;
os_free(peer->vht_capabilities);
peer->vht_capabilities = NULL;
+ os_free(peer->he_capabilities);
+ peer->he_capabilities = NULL;
os_free(peer->ext_capab);
peer->ext_capab = NULL;
os_free(peer->supp_channels);
@@ -1154,7 +1159,7 @@ skip_rsnie:
rbuf = os_zalloc(buf_len + 1);
if (rbuf == NULL) {
wpa_tdls_peer_free(sm, peer);
- return -1;
+ return -2;
}
pos = rbuf;
@@ -1173,7 +1178,7 @@ skip_rsnie:
"TDLS: Failed to get random data for initiator Nonce");
os_free(rbuf);
wpa_tdls_peer_free(sm, peer);
- return -1;
+ return -2;
}
peer->tk_set = 0; /* A new nonce results in a new TK */
wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
@@ -1413,6 +1418,8 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
skip_ies:
+ if (peer->he_capabilities)
+ peer_capab |= TDLS_PEER_HE;
if (peer->vht_capabilities)
peer_capab |= TDLS_PEER_VHT;
if (peer->ht_capabilities)
@@ -1651,6 +1658,29 @@ static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
}
+static int copy_peer_he_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->he_capabilities) {
+ wpa_printf(MSG_DEBUG, "TDLS: No HE capabilities received");
+ return 0;
+ }
+
+ os_free(peer->he_capabilities);
+ peer->he_capab_len = 0;
+ peer->he_capabilities = os_memdup(kde->he_capabilities,
+ kde->he_capab_len);
+ if (!peer->he_capabilities)
+ return -1;
+
+ peer->he_capab_len = kde->he_capab_len;
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HE capabilities",
+ peer->he_capabilities, peer->he_capab_len);
+
+ return 0;
+}
+
+
static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
struct wpa_tdls_peer *peer)
{
@@ -1760,6 +1790,8 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
peer->supp_rates, peer->supp_rates_len,
peer->ht_capabilities,
peer->vht_capabilities,
+ peer->he_capabilities,
+ peer->he_capab_len,
peer->qos_info, peer->wmm_capable,
peer->ext_capab, peer->ext_capab_len,
peer->supp_channels,
@@ -1895,7 +1927,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
if (copy_peer_ht_capab(&kde, peer) < 0)
goto error;
- if (copy_peer_vht_capab(&kde, peer) < 0)
+ if (copy_peer_vht_capab(&kde, peer) < 0 ||
+ copy_peer_he_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -1924,8 +1957,12 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
"TDLS setup - send own request");
peer->initiator = 1;
wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
- NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
- wpa_tdls_send_tpk_m1(sm, peer);
+ NULL, NULL, 0, 0, 0, NULL, 0, NULL, 0,
+ NULL, 0);
+ if (wpa_tdls_send_tpk_m1(sm, peer) == -2) {
+ peer = NULL;
+ goto error;
+ }
}
if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
@@ -2299,7 +2336,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (copy_peer_ht_capab(&kde, peer) < 0)
goto error;
- if (copy_peer_vht_capab(&kde, peer) < 0)
+ if (copy_peer_vht_capab(&kde, peer) < 0 ||
+ copy_peer_he_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -2653,6 +2691,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
int tdls_prohibited = sm->tdls_prohibited;
+ int res;
if (sm->tdls_disabled || !sm->tdls_supported)
return -1;
@@ -2685,15 +2724,18 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
/* add the peer to the driver as a "setup in progress" peer */
if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
- NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ NULL, NULL, 0, 0, 0, NULL, 0, NULL, 0,
+ NULL, 0)) {
wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
peer->tpk_in_progress = 1;
- if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
+ res = wpa_tdls_send_tpk_m1(sm, peer);
+ if (res < 0) {
+ if (res != -2)
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2806,6 +2848,11 @@ int wpa_tdls_init(struct wpa_sm *sm)
if (sm == NULL)
return -1;
+ if (sm->l2_tdls) {
+ l2_packet_deinit(sm->l2_tdls);
+ sm->l2_tdls = NULL;
+ }
+
sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
sm->ifname,
sm->own_addr,
diff --git a/contrib/wpa/src/rsn_supp/wpa.c b/contrib/wpa/src/rsn_supp/wpa.c
index c929e8194a03..e01cd52177d2 100644
--- a/contrib/wpa/src/rsn_supp/wpa.c
+++ b/contrib/wpa/src/rsn_supp/wpa.c
@@ -21,6 +21,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "drivers/driver.h"
@@ -183,6 +185,14 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
+ if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
@@ -441,6 +451,10 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
NULL, 0, &buflen, NULL);
if (buf) {
+ /* Set and reset eapFail to allow EAP state machine to
+ * proceed with new authentication. */
+ eapol_sm_notify_eap_fail(sm->eapol, true);
+ eapol_sm_notify_eap_fail(sm->eapol, false);
wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
buf, buflen);
os_free(buf);
@@ -488,6 +502,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
int res;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE before FT processing",
+ wpa_ie, wpa_ie_len);
/*
* Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
* FTIE from (Re)Association Response.
@@ -503,8 +519,14 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
os_free(rsn_ie_buf);
return -1;
}
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: WPA IE after PMKID[PMKR1Name] addition into RSNE",
+ rsn_ie_buf, wpa_ie_len);
if (sm->assoc_resp_ies) {
+ wpa_hexdump(MSG_DEBUG, "WPA: Add assoc_resp_ies",
+ sm->assoc_resp_ies,
+ sm->assoc_resp_ies_len);
os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
sm->assoc_resp_ies_len);
wpa_ie_len += sm->assoc_resp_ies_len;
@@ -561,7 +583,8 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
+ int akmp;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
@@ -575,10 +598,73 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->key_mgmt;
+#ifdef CONFIG_OWE
+ if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE &&
+ sm->pmk_len > 32) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Force SHA256 for PTK derivation");
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
+ }
+#endif /* CONFIG_OWE */
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
- key->key_nonce, ptk, sm->key_mgmt,
- sm->pairwise_cipher, z, z_len);
+ key->key_nonce, ptk, akmp,
+ sm->pairwise_cipher, z, z_len,
+ kdk_len);
+}
+
+
+static int wpa_handle_ext_key_id(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *kde)
+{
+ if (sm->ext_key_id) {
+ u16 key_id;
+
+ if (!kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx,
+ sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
+ "RSN: No Key ID in Extended Key ID handshake");
+ sm->keyidx_active = 0;
+ return sm->use_ext_key_id ? -1 : 0;
+ }
+
+ key_id = kde->key_id[0] & 0x03;
+ if (key_id > 1) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid Extended Key ID: %d", key_id);
+ return -1;
+ }
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Using Extended Key ID %d", key_id);
+ sm->keyidx_active = key_id;
+ sm->use_ext_key_id = 1;
+ } else {
+ if (kde->key_id && (kde->key_id[0] & 0x03)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
+ return -1;
+ }
+
+ if (kde->key_id) {
+ /* This is not supposed to be included here, but ignore
+ * the case of matching Key ID 0 just in case. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Extended Key ID Key ID 0 in PTK0 handshake");
+ }
+ sm->keyidx_active = 0;
+ sm->use_ext_key_id = 0;
+ }
+
+ return 0;
}
@@ -600,6 +686,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
return;
}
+ if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -655,54 +749,84 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+ kde_buf = os_malloc(kde_len +
+ 2 + RSN_SELECTOR_LEN + 3 +
+ sm->assoc_rsnxe_len +
+ 2 + RSN_SELECTOR_LEN + 1 +
+ 2 + RSN_SELECTOR_LEN + 2);
+ if (!kde_buf)
+ goto failed;
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
+ pos = kde + kde_len;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
-
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
- if (!kde_buf) {
- wpa_printf(MSG_WARNING,
- "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
- goto failed;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_eapol);
+ ci.frequency = sm->oci_freq_override_eapol;
}
+#endif /* CONFIG_TESTING_OPTIONS */
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
kde_len = pos - kde;
}
#endif /* CONFIG_OCV */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
+ os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ kde_len += sm->assoc_rsnxe_len;
+ }
+
#ifdef CONFIG_P2P
if (sm->p2p) {
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
- if (kde_buf) {
- u8 *pos;
- wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
- "into EAPOL-Key 2/4");
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + 1;
- RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
- pos += RSN_SELECTOR_LEN;
- *pos++ = 0x01;
- kde_len = pos - kde;
- }
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && sm->key_mgmt == WPA_KEY_MGMT_DPP) {
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "DPP: Add DPP KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 2;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_DPP);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = DPP_VERSION; /* Protocol Version */
+ *pos = 0; /* Flags */
+ if (sm->dpp_pfs == 0)
+ *pos |= DPP_KDE_PFS_ALLOWED;
+ else if (sm->dpp_pfs == 1)
+ *pos |= DPP_KDE_PFS_ALLOWED | DPP_KDE_PFS_REQUIRED;
+ pos++;
+ kde_len = pos - kde;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
kde, kde_len, ptk) < 0)
goto failed;
@@ -739,11 +863,11 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
wpa_sm_mlme_setprotection(
sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
if (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
sm->key_mgmt == WPA_KEY_MGMT_DPP ||
sm->key_mgmt == WPA_KEY_MGMT_OWE)
- eapol_sm_notify_eap_success(sm->eapol, TRUE);
+ eapol_sm_notify_eap_success(sm->eapol, true);
/*
* Start preauthentication after a short wait to avoid a
* possible race condition between the data receive and key
@@ -781,7 +905,8 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ enum key_flag key_flag)
{
int keylen, rsclen;
enum wpa_alg alg;
@@ -825,15 +950,20 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
+ rsclen, sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE | key_flag) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to set PTK to the "
- "driver (alg=%d keylen=%d bssid=" MACSTR ")",
- alg, keylen, MAC2STR(sm->bssid));
+ "WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+ MACSTR " idx=%d key_flag=0x%x)",
+ alg, keylen, MAC2STR(sm->bssid),
+ sm->keyidx_active, key_flag);
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
sm->ptk.tk_len = 0;
@@ -844,7 +974,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
sm, NULL);
}
+ return 0;
+}
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
+ sm->keyidx_active, MAC2STR(sm->bssid));
+
+ if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to activate PTK for TX (idx=%d bssid="
+ MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+ return -1;
+ }
return 0;
}
@@ -919,7 +1065,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
if (wpa_sm_set_key(sm, gd->alg, NULL,
gd->keyidx, 1, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
@@ -928,7 +1075,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1051,7 +1198,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
}
-#ifdef CONFIG_IEEE80211W
static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
const struct wpa_igtk_kde *igtk,
int wnm_sleep)
@@ -1083,7 +1229,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, len) < 0) {
+ igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
if (keyidx == 0x0400 || keyidx == 0x0500) {
/* Assume the AP has broken PMF implementation since it
* seems to have swapped the KeyID bytes. The AP cannot
@@ -1118,18 +1264,69 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
return 0;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+ const struct wpa_bigtk_kde *bigtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->bigtk.bigtk_len == len &&
+ os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+ sm->bigtk.bigtk_len) == 0) ||
+ (sm->bigtk_wnm_sleep.bigtk_len == len &&
+ os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(bigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+ if (keyidx < 6 || keyidx > 7) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid BIGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+ bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure BIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->bigtk_wnm_sleep.bigtk_len = len;
+ os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len);
+ } else {
+ sm->bigtk.bigtk_len = len;
+ os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+ }
+
+ return 0;
+}
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
-#ifdef CONFIG_IEEE80211W
- if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
+ size_t len;
+
+ if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
+ sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED)
return 0;
if (ie->igtk) {
- size_t len;
const struct wpa_igtk_kde *igtk;
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1141,10 +1338,19 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
return -1;
}
+ if (ie->bigtk && sm->beacon_prot) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+ return -1;
+
+ bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+ if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+ return -1;
+ }
+
return 0;
-#else /* CONFIG_IEEE80211W */
- return 0;
-#endif /* CONFIG_IEEE80211W */
}
@@ -1330,11 +1536,10 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Could not find AP from "
"the scan results");
- } else {
- wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Found the current AP from "
- "updated scan results");
+ return -1;
}
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Found the current AP from updated scan results");
}
if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
@@ -1371,6 +1576,22 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1;
}
+ if (sm->proto == WPA_PROTO_RSN &&
+ ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0)))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+ ie->rsnxe, ie->rsnxe_len);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -1455,7 +1676,6 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
"WPA: GTK IE in unencrypted key data");
goto failed;
}
-#ifdef CONFIG_IEEE80211W
if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: IGTK KDE in unencrypted key data");
@@ -1463,6 +1683,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
if (ie.igtk &&
+ sm->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED &&
wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
(unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
@@ -1471,11 +1692,13 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
(unsigned long) ie.igtk_len);
goto failed;
}
-#endif /* CONFIG_IEEE80211W */
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
+ if (wpa_handle_ext_key_id(sm, &ie))
+ goto failed;
+
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1513,14 +1736,33 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-m3 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && ie.dpp_kde) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: peer Protocol Version %u Flags 0x%x",
+ ie.dpp_kde[0], ie.dpp_kde[1]);
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_pfs != 2 &&
+ (ie.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) && !sm->dpp_z) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
+ goto failed;
+ }
+ }
+#endif /* CONFIG_DPP2 */
+
+ if (sm->use_ext_key_id &&
+ wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
+ goto failed;
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@@ -1532,7 +1774,14 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- if (wpa_supplicant_install_ptk(sm, key))
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_supplicant_activate_ptk(sm);
+ else
+ res = wpa_supplicant_install_ptk(sm, key,
+ KEY_FLAG_RX_TX);
+ if (res)
goto failed;
}
@@ -1540,7 +1789,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_sm_mlme_setprotection(
sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1588,6 +1837,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->cur_pmksa = sa;
}
+ if (ie.transition_disable)
+ wpa_sm_transition_disable(sm, ie.transition_disable[0]);
sm->msg_3_of_4_ok = 1;
return;
@@ -1604,6 +1855,7 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
{
int maxkeylen;
struct wpa_eapol_ie_parse ie;
+ u16 gtk_len;
wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
keydata, keydatalen);
@@ -1619,7 +1871,20 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
"WPA: No GTK IE in Group Key msg 1/2");
return -1;
}
- maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+ gtk_len = ie.gtk_len;
+ if (gtk_len < 2) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid GTK KDE length (%u) in Group Key msg 1/2",
+ gtk_len);
+ return -1;
+ }
+ gtk_len -= 2;
+ if (gtk_len > sizeof(gd->gtk)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Too long GTK in GTK KDE (len=%u)", gtk_len);
+ return -1;
+ }
+ maxkeylen = gd->gtk_len = gtk_len;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
@@ -1633,31 +1898,26 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-g1 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
#endif /* CONFIG_OCV */
if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in group key handshake",
- ie.gtk, ie.gtk_len);
+ ie.gtk, 2 + gtk_len);
gd->keyidx = ie.gtk[0] & 0x3;
gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
!!(ie.gtk[0] & BIT(2)));
- if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "RSN: Too long GTK in GTK IE (len=%lu)",
- (unsigned long) ie.gtk_len - 2);
- return -1;
- }
- os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+ os_memcpy(gd->gtk, ie.gtk + 2, gtk_len);
if (ieee80211w_set_keys(sm, &ie) < 0)
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1806,6 +2066,15 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
os_free(rbuf);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol_g2) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_eapol_g2);
+ ci.frequency = sm->oci_freq_override_eapol_g2;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = key_mic + mic_len + 2; /* Key Data */
if (ocv_insert_oci_kde(&ci, &pos) < 0) {
@@ -2076,6 +2345,16 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm)
}
+void wpa_sm_aborted_external_cached(struct wpa_sm *sm)
+{
+ if (sm && sm->cur_pmksa && sm->cur_pmksa->external) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cancelling external PMKSA caching attempt");
+ sm->cur_pmksa = NULL;
+ }
+}
+
+
static void wpa_eapol_key_dump(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
unsigned int key_data_len,
@@ -2209,13 +2488,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
u8 *tmp = NULL;
int ret = -1;
u8 *mic, *key_data;
- size_t mic_len, keyhdrlen;
+ size_t mic_len, keyhdrlen, pmk_len;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ pmk_len = sm->pmk_len;
+ if (!pmk_len && sm->cur_pmksa)
+ pmk_len = sm->cur_pmksa->pmk_len;
+ mic_len = wpa_mic_len(sm->key_mgmt, pmk_len);
keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
@@ -2294,9 +2576,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2324,7 +2604,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
} else
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) {
@@ -2333,11 +2612,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
"negotiated AES-128-CMAC");
goto out;
}
- } else
-#endif /* CONFIG_IEEE80211W */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_use_akm_defined(sm->key_mgmt) &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2", ver);
@@ -2480,12 +2757,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
case WPA_KEY_MGMT_FT_PSK:
return RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_CCKM:
return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_CCKM:
@@ -2518,7 +2793,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
char pmkid_txt[PMKID_LEN * 2 + 1];
- int rsna, ret;
+ bool rsna;
+ int ret;
size_t len;
if (sm->cur_pmksa) {
@@ -2527,12 +2803,9 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
} else
pmkid_txt[0] = '\0';
- if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
- wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
- sm->proto == WPA_PROTO_RSN)
- rsna = 1;
- else
- rsna = 0;
+ rsna = (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+ wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
+ sm->proto == WPA_PROTO_RSN;
ret = os_snprintf(buf, buflen,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -2677,8 +2950,10 @@ void wpa_sm_deinit(struct wpa_sm *sm)
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
os_free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_rsnxe);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ os_free(sm->ap_rsnxe);
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
#ifdef CONFIG_IEEE80211R
@@ -2733,7 +3008,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
* Clear portValid to kick EAPOL state machine to re-enter
* AUTHENTICATED state to get the EAPOL port Authorized.
*/
- eapol_sm_notify_portValid(sm->eapol, FALSE);
+ eapol_sm_notify_portValid(sm->eapol, false);
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
/* Prepare for the next transition */
@@ -2768,10 +3043,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
}
#ifdef CONFIG_TDLS
@@ -2781,6 +3054,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
+
+ sm->keyidx_active = 0;
}
@@ -2812,6 +3087,7 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
+ sm->keyidx_active = 0;
sm->msg_3_of_4_ok = 0;
os_memset(sm->bssid, 0, ETH_ALEN);
@@ -2907,7 +3183,7 @@ void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
/**
- * wpa_sm_set_config - Notification of current configration change
+ * wpa_sm_set_config - Notification of current configuration change
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @config: Pointer to current network configuration
*
@@ -2934,6 +3210,8 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+ sm->owe_ptk_workaround = config->owe_ptk_workaround;
+ sm->force_kdk_derivation = config->force_kdk_derivation;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -2943,6 +3221,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->fils_cache_id_set = 0;
}
#endif /* CONFIG_FILS */
+ sm->beacon_prot = config->beacon_prot;
} else {
sm->network_ctx = NULL;
sm->allowed_pairwise_cipher = 0;
@@ -2953,6 +3232,9 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
sm->wpa_rsc_relaxation = 0;
+ sm->owe_ptk_workaround = 0;
+ sm->beacon_prot = 0;
+ sm->force_kdk_derivation = false;
}
}
@@ -3043,11 +3325,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_KEY_MGMT:
sm->key_mgmt = value;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_PARAM_MGMT_GROUP:
sm->mgmt_group_cipher = value;
break;
-#endif /* CONFIG_IEEE80211W */
case WPA_PARAM_RSN_ENABLED:
sm->rsn_enabled = value;
break;
@@ -3057,6 +3337,43 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
+ case WPA_PARAM_SAE_PK:
+ sm->sae_pk = value;
+ break;
+ case WPA_PARAM_DENY_PTK0_REKEY:
+ sm->wpa_deny_ptk0_rekey = value;
+ break;
+ case WPA_PARAM_EXT_KEY_ID:
+ sm->ext_key_id = value;
+ break;
+ case WPA_PARAM_USE_EXT_KEY_ID:
+ sm->use_ext_key_id = value;
+ break;
+#ifdef CONFIG_TESTING_OPTIONS
+ case WPA_PARAM_FT_RSNXE_USED:
+ sm->ft_rsnxe_used = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_EAPOL:
+ sm->oci_freq_override_eapol = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_EAPOL_G2:
+ sm->oci_freq_override_eapol_g2 = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FT_ASSOC:
+ sm->oci_freq_override_ft_assoc = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
+ sm->oci_freq_override_fils_assoc = value;
+ break;
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ case WPA_PARAM_DPP_PFS:
+ sm->dpp_pfs = value;
+ break;
+#endif /* CONFIG_DPP2 */
default:
break;
}
@@ -3094,6 +3411,15 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
return pos - buf;
pos += ret;
+#ifdef CONFIG_DPP2
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ ret = os_snprintf(pos, end - pos, "dpp_pfs=1\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_DPP2 */
+
if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
struct wpa_ie_data rsn;
if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
@@ -3131,6 +3457,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
+int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return sm ? sm->ext_key_id : 0;
+}
+
+
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return sm ? sm->use_ext_key_id : 0;
+}
+
+
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
@@ -3235,6 +3573,83 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
/**
+ * wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @rsnxe: Pointer to buffer for RSNXE
+ * @rsnxe_len: Pointer to the length of the rsne buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len)
+{
+ int res;
+
+ if (!sm)
+ return -1;
+
+ res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
+ if (res < 0)
+ return -1;
+ *rsnxe_len = res;
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
+
+ if (sm->assoc_rsnxe) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Leave previously set RSNXE default",
+ sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ } else if (*rsnxe_len > 0) {
+ /*
+ * Make a copy of the RSNXE so that 4-Way Handshake gets the
+ * correct version of the IE even if it gets changed.
+ */
+ sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = *rsnxe_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in (Re)Association Request
+ * frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_rsnxe_default().
+ */
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->assoc_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: clearing own RSNXE");
+ sm->assoc_rsnxe = NULL;
+ sm->assoc_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
+ sm->assoc_rsnxe = os_memdup(ie, len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
@@ -3303,6 +3718,39 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
/**
+ * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
+ sm->ap_rsnxe = NULL;
+ sm->ap_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
+ sm->ap_rsnxe = os_memdup(ie, len);
+ if (!sm->ap_rsnxe)
+ return -1;
+
+ sm->ap_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @data: Pointer to data area for parsing results
@@ -3364,6 +3812,16 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
}
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp)
+{
+ return pmksa_cache_get(sm->pmksa, aa, pmkid, network_ctx, akmp);
+}
+
+
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -3375,10 +3833,8 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
@@ -3386,6 +3842,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
sm->pmk_r0_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
sm->pmk_r1_len = 0;
+#ifdef CONFIG_PASN
+ os_free(sm->pasn_r1kh);
+ sm->pasn_r1kh = NULL;
+ sm->n_pasn_r1kh = 0;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
}
@@ -3398,6 +3859,14 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
}
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+ if (!sm)
+ return 0;
+ return sm->ptk.installed;
+}
+
+
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
{
os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
@@ -3406,7 +3875,13 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
{
- pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, false);
+}
+
+
+void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, true);
}
@@ -3452,14 +3927,19 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
return -1;
}
forced_memzero(&gd, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
const struct wpa_igtk_kde *igtk;
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+ if (sm->beacon_prot &&
+ wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -3643,13 +4123,13 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
sm->fils_erp_pmkid_set = 0;
if (erp_msg) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(buf, erp_msg);
/* Calculate pending PMKID here so that we do not need to
* maintain a copy of the EAP-Initiate/Reauth message. */
@@ -3683,7 +4163,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
const u8 *g_sta = NULL;
size_t g_sta_len = 0;
const u8 *g_ap = NULL;
- size_t g_ap_len = 0;
+ size_t g_ap_len = 0, kdk_len;
struct wpabuf *pub = NULL;
os_memcpy(sm->bssid, bssid, ETH_ALEN);
@@ -3854,16 +4334,16 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
- /* FILS Wrapped Data */
- if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (!sm->cur_pmksa && elems.wrapped_data) {
u8 rmsk[ERP_MAX_KEY_LEN];
size_t rmsk_len;
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
- eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data,
+ elems.wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
goto fail;
@@ -3911,13 +4391,21 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
sm->fils_nonce, sm->fils_anonce,
dh_ss ? wpabuf_head(dh_ss) : NULL,
dh_ss ? wpabuf_len(dh_ss) : 0,
&sm->ptk, ick, &ick_len,
sm->key_mgmt, sm->pairwise_cipher,
- sm->fils_ft, &sm->fils_ft_len) < 0) {
+ sm->fils_ft, &sm->fils_ft_len,
+ kdk_len) < 0) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
goto fail;
}
@@ -4019,12 +4507,14 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -4046,10 +4536,6 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
return -1;
}
sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
MAC2STR(sm->r1kh_id));
pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
@@ -4058,17 +4544,13 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
/* Management Group Cipher Suite */
pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = ((u8 *) wpabuf_put(buf, 0) - (u8 *) rsnie) - 2;
return 0;
@@ -4172,6 +4654,15 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
wpabuf_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_fils_assoc);
+ ci.frequency = sm->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -4376,8 +4867,10 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=fils-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
goto fail;
}
}
@@ -4454,11 +4947,12 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
keylen, (long unsigned int) sm->ptk.tk_len);
goto fail;
}
+
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
sm->ptk.tk, keylen);
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
MACSTR ")",
@@ -4466,6 +4960,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
goto fail;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TODO: TK could be cleared after auth frame exchange now that driver
* takes care of association frame encryption/decryption. */
/* TK is not needed anymore in supplicant */
@@ -4482,6 +4979,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
sm->fils_completed = 1;
forced_memzero(&gd, sizeof(gd));
+ if (kde.transition_disable)
+ wpa_sm_transition_disable(sm, kde.transition_disable[0]);
+
return 0;
fail:
forced_memzero(&gd, sizeof(gd));
@@ -4735,3 +5235,14 @@ void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_PASN
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt)
+{
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
+ bssid, sm->own_addr, NULL,
+ key_mgmt, 0);
+}
+#endif /* CONFIG_PASN */
diff --git a/contrib/wpa/src/rsn_supp/wpa.h b/contrib/wpa/src/rsn_supp/wpa.h
index ae9cd6484baa..ff8a85b6e29b 100644
--- a/contrib/wpa/src/rsn_supp/wpa.h
+++ b/contrib/wpa/src/rsn_supp/wpa.h
@@ -27,10 +27,11 @@ struct wpa_sm_ctx {
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
void (*deauthenticate)(void * ctx, u16 reason_code);
+ void (*reconnect)(void *ctx);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
void * (*get_network_ctx)(void *ctx);
int (*get_bssid)(void *ctx, u8 *bssid);
int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
@@ -41,7 +42,8 @@ struct wpa_sm_ctx {
size_t *msg_len, void **data_pos);
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len);
+ const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold, int akmp);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -67,6 +69,8 @@ struct wpa_sm_ctx {
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len,
@@ -84,6 +88,9 @@ struct wpa_sm_ctx {
void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ void (*transition_disable)(void *ctx, u8 bitmap);
+ void (*store_ptk)(void *ctx, u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
};
@@ -98,7 +105,18 @@ enum wpa_sm_conf_params {
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
WPA_PARAM_MFP,
- WPA_PARAM_OCV
+ WPA_PARAM_OCV,
+ WPA_PARAM_SAE_PWE,
+ WPA_PARAM_SAE_PK,
+ WPA_PARAM_DENY_PTK0_REKEY,
+ WPA_PARAM_EXT_KEY_ID,
+ WPA_PARAM_USE_EXT_KEY_ID,
+ WPA_PARAM_FT_RSNXE_USED,
+ WPA_PARAM_DPP_PFS,
+ WPA_PARAM_OCI_FREQ_EAPOL,
+ WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ WPA_PARAM_OCI_FREQ_FILS_ASSOC,
};
struct rsn_supp_config {
@@ -110,9 +128,13 @@ struct rsn_supp_config {
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
const u8 *fils_cache_id;
+ int beacon_prot;
+ bool force_kdk_derivation;
};
#ifndef CONFIG_NO_WPA
@@ -134,8 +156,12 @@ void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len);
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len);
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -144,6 +170,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ext_key_id(struct wpa_sm *sm);
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm);
int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -152,6 +180,7 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data);
void wpa_sm_aborted_cached(struct wpa_sm *sm);
+void wpa_sm_aborted_external_cached(struct wpa_sm *sm);
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len);
int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
@@ -166,11 +195,18 @@ void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
@@ -260,6 +296,12 @@ static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
return -1;
}
+static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;
@@ -283,6 +325,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
+static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return 0;
+}
+
+static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
return 0;
@@ -303,6 +355,10 @@ static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
{
}
+static inline void wpa_sm_aborted_external_cached(struct wpa_sm *sm)
+{
+}
+
static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -325,6 +381,13 @@ static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
{
}
+static inline struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *aa, const u8 *pmkid,
+ const void *network_ctx, int akmp)
+{
+ return NULL;
+}
+
static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
{
return 0;
@@ -335,6 +398,11 @@ static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
{
}
+static inline void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm,
+ void *network_ctx)
+{
+}
+
static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
void *network_ctx)
{
@@ -375,6 +443,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
const u8 *mdie);
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name);
+
+#endif /* CONFIG_PASN */
+
#else /* CONFIG_IEEE80211R */
static inline int
@@ -418,6 +493,16 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ return -1;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
@@ -466,5 +551,7 @@ int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set);
void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id);
void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt);
#endif /* WPA_H */
diff --git a/contrib/wpa/src/rsn_supp/wpa_ft.c b/contrib/wpa/src/rsn_supp/wpa_ft.c
index 46ffdca67a77..2669da9b3fa8 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ft.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ft.c
@@ -15,13 +15,24 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
+#include "wpa_ie.h"
#include "pmksa_cache.h"
#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_PASN
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid);
+#else /* CONFIG_PASN */
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+#endif /* CONFIG_PASN */
+
+
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
@@ -29,7 +40,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const u8 *anonce = key->key_nonce;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *mpmk;
- size_t mpmk_len;
+ size_t mpmk_len, kdk_len;
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
@@ -49,20 +60,25 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
sm->pmk_r1_len = sm->pmk_r0_len;
if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
+
+ wpa_ft_pasn_store_r1kh(sm, src_addr);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher);
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher,
+ kdk_len);
}
@@ -81,23 +97,30 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
if (sm == NULL)
return 0;
+ if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+ os_free(sm->assoc_resp_ies);
+ sm->assoc_resp_ies = NULL;
+ sm->assoc_resp_ies_len = 0;
+ os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+ sm->r0kh_id_len = 0;
+ os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+ return 0;
+ }
+
use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1;
- if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+ if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
return -1;
- if (ft.mdie) {
- wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
- ft.mdie, MOBILITY_DOMAIN_ID_LEN);
- os_memcpy(sm->mobility_domain, ft.mdie,
- MOBILITY_DOMAIN_ID_LEN);
- sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
- wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
- sm->mdie_ft_capab);
- } else
- os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+ ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+ wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+ sm->mdie_ft_capab);
if (ft.r0kh_id) {
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
@@ -124,10 +147,10 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
if (sm->assoc_resp_ies) {
u8 *pos = sm->assoc_resp_ies;
- if (ft.mdie) {
- os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
- pos += ft.mdie_len + 2;
- }
+
+ os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+ pos += ft.mdie_len + 2;
+
if (ft.ftie) {
os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
pos += ft.ftie_len + 2;
@@ -154,6 +177,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
* @ap_mdie: Mobility Domain IE from the target AP
+ * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame
* Returns: Pointer to buffer with IEs or %NULL on failure
*
* Caller is responsible for freeing the returned buffer with os_free();
@@ -163,14 +187,17 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *kck, size_t kck_len,
const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
- const u8 *ap_mdie)
+ const u8 *ap_mdie, int omit_rsnxe)
{
size_t buf_len;
u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
struct rsn_ie_hdr *rsnie;
- u16 capab;
int mdie_len;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
+ int rsnxe_used;
+ int res;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
@@ -245,17 +272,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256 ||
- sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
- capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
/* PMKID Count */
@@ -266,7 +283,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
pos += WPA_PMK_NAME_LEN;
-#ifdef CONFIG_IEEE80211W
/* Management Group Cipher Suite */
switch (sm->mgmt_group_cipher) {
case WPA_CIPHER_AES_128_CMAC:
@@ -286,7 +302,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += RSN_SELECTOR_LEN;
break;
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
@@ -303,10 +318,20 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
+ rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (anonce && sm->ft_rsnxe_used) {
+ rsnxe_used = sm->ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
struct rsn_ftie_sha384 *ftie;
ftie = (struct rsn_ftie_sha384 *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -317,6 +342,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -347,6 +373,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
os_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_ft_assoc);
+ ci.frequency = sm->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
*pos++ = FTIE_SUBELEM_OCI;
*pos++ = OCV_OCI_LEN;
@@ -364,6 +398,17 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += ric_ies_len;
}
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
+ }
+
if (kck) {
/*
* IEEE Std 802.11r-2008, 11A.8.4
@@ -375,14 +420,18 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
* MDIE
* FTIE (with MIC field set to 0)
* RIC-Request (if present)
+ * RSNXE (if present)
*/
/* Information element count */
*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
+ if (rsnxe_len)
+ *elem_count += 1;
if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
- ric_ies_len, fte_mic) < 0) {
+ ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
+ fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -412,12 +461,15 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
- if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
+ (u8 *) sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
return 0;
}
@@ -440,7 +492,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie, 0);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -494,7 +546,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ret;
const u8 *bssid;
const u8 *kck;
- size_t kck_len;
+ size_t kck_len, kdk_len;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce;
@@ -598,6 +650,12 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
+ if (sm->mfp == 2 && !(parse.rsn_capab & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_INFO,
+ "FT: Target AP does not support PMF, but local configuration requires that");
+ return -1;
+ }
+
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
@@ -608,15 +666,23 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name) < 0)
return -1;
sm->pmk_r1_len = sm->pmk_r0_len;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
- sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
+
+ wpa_ft_pasn_store_r1kh(sm, bssid);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
anonce, sm->own_addr, bssid,
sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
- sm->pairwise_cipher) < 0)
+ sm->pairwise_cipher,
+ kdk_len) < 0)
return -1;
if (wpa_key_mgmt_fils(sm->key_mgmt)) {
@@ -630,7 +696,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name,
kck, kck_len, bssid,
ric_ies, ric_ies_len,
- parse.mdie ? parse.mdie - 2 : NULL);
+ parse.mdie ? parse.mdie - 2 : NULL,
+ !sm->ap_rsnxe);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -757,7 +824,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
os_memcpy(gtk + 24, tmp, 8);
}
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
- gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+ gtk_elem + 3, rsc_len, gtk, keylen,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
"driver.");
return -1;
@@ -767,7 +835,6 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
}
-#ifdef CONFIG_IEEE80211W
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
@@ -825,7 +892,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
igtk_len);
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr, keyidx, 0,
- igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+ igtk_elem + 2, 6, igtk, igtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
forced_memzero(igtk, sizeof(igtk));
@@ -835,7 +903,74 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
return 0;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+ size_t bigtk_elem_len)
+{
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+ u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->beacon_prot || !bigtk_elem ||
+ (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256))
+ return 0;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+ bigtk_elem, bigtk_elem_len);
+
+ bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem length %lu",
+ (unsigned long) bigtk_elem_len);
+ return -1;
+ }
+ if (bigtk_elem[8] != bigtk_len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem Key Length %d",
+ bigtk_elem[8]);
+ return -1;
+ }
+
+ if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt BIGTK");
+ return -1;
+ }
+
+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+ keyidx = WPA_GET_LE16(bigtk_elem);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+ bigtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ bigtk_elem + 2, 6, bigtk, bigtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set BIGTK to the driver");
+ forced_memzero(bigtk, sizeof(bigtk));
+ return -1;
+ }
+ forced_memzero(bigtk, sizeof(bigtk));
+
+ return 0;
+}
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
@@ -850,6 +985,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int own_rsnxe_used, rsnxe_used;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -888,6 +1024,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -901,6 +1038,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -962,6 +1100,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -982,6 +1122,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return -1;
@@ -994,6 +1136,58 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
+ if (rsnxe_used && !sm->ap_rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames");
+ return -1;
+ }
+
+ if (!sm->ap_rsn_ie) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: No RSNE for this AP known - trying to get from scan results");
+ if (wpa_sm_get_beacon_ie(sm) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FT: Could not find AP from the scan results");
+ return -1;
+ }
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: Found the current AP from updated scan results");
+ }
+
+ if (sm->ap_rsn_ie &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ parse.rsn - 2, parse.rsn_len + 2)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE in FT protocol Reassociation Response frame",
+ parse.rsn ? parse.rsn - 2 : NULL,
+ parse.rsn ? parse.rsn_len + 2 : 0);
+ return -1;
+ }
+
+ own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+ if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) ||
+ (!sm->ap_rsnxe && parse.rsnxe) ||
+ (sm->ap_rsnxe && parse.rsnxe &&
+ (sm->ap_rsnxe_len != 2 + parse.rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2,
+ sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNXE in FT protocol Reassociation Response frame",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
+ return -1;
+ }
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
@@ -1006,8 +1200,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=ft-assoc error=%s",
+ MAC2STR(src_addr), ocv_errorstr);
return -1;
}
}
@@ -1015,13 +1211,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
sm->ft_reassoc_completed = 1;
- if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
- return -1;
-
-#ifdef CONFIG_IEEE80211W
- if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+ wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
if (sm->set_ptk_after_assoc) {
wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
@@ -1067,7 +1260,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie, 0);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
@@ -1078,4 +1271,88 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
return 0;
}
+
+#ifdef CONFIG_PASN
+
+static struct pasn_ft_r1kh * wpa_ft_pasn_get_r1kh(struct wpa_sm *sm,
+ const u8 *bssid)
+{
+ size_t i;
+
+ for (i = 0; i < sm->n_pasn_r1kh; i++)
+ if (os_memcmp(sm->pasn_r1kh[i].bssid, bssid, ETH_ALEN) == 0)
+ return &sm->pasn_r1kh[i];
+
+ return NULL;
+}
+
+
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+ struct pasn_ft_r1kh *tmp = wpa_ft_pasn_get_r1kh(sm, bssid);
+
+ if (tmp)
+ return;
+
+ tmp = os_realloc_array(sm->pasn_r1kh, sm->n_pasn_r1kh + 1,
+ sizeof(*tmp));
+ if (!tmp) {
+ wpa_printf(MSG_DEBUG, "PASN: FT: Failed to store R1KH");
+ return;
+ }
+
+ sm->pasn_r1kh = tmp;
+ tmp = &sm->pasn_r1kh[sm->n_pasn_r1kh];
+
+ wpa_printf(MSG_DEBUG, "PASN: FT: Store R1KH for " MACSTR,
+ MAC2STR(bssid));
+
+ os_memcpy(tmp->bssid, bssid, ETH_ALEN);
+ os_memcpy(tmp->r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN);
+
+ sm->n_pasn_r1kh++;
+}
+
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *bssid,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ struct pasn_ft_r1kh *r1kh_entry;
+
+ if (sm->key_mgmt != (unsigned int) akmp) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Key management mismatch: %u != %u",
+ sm->key_mgmt, akmp);
+ return -1;
+ }
+
+ r1kh_entry = wpa_ft_pasn_get_r1kh(sm, bssid);
+ if (!r1kh_entry) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Cannot find R1KH-ID for " MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
+ /*
+ * Note: PMK R0 etc. were already derived and are maintained by the
+ * state machine, and as the same key hierarchy is used, there is no
+ * need to derive them again, so only derive PMK R1 etc.
+ */
+ if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+ r1kh_entry->r1kh_id, sm->own_addr, pmk_r1,
+ pmk_r1_name) < 0)
+ return -1;
+
+ *pmk_r1_len = sm->pmk_r0_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: FT: PMK-R1", pmk_r1, sm->pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "PASN: FT: PMKR1Name", pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
diff --git a/contrib/wpa/src/rsn_supp/wpa_i.h b/contrib/wpa/src/rsn_supp/wpa_i.h
index d86734b0df55..e7281bf3b1d8 100644
--- a/contrib/wpa/src/rsn_supp/wpa_i.h
+++ b/contrib/wpa/src/rsn_supp/wpa_i.h
@@ -14,6 +14,11 @@
struct wpa_tdls_peer;
struct wpa_eapol_key;
+struct pasn_ft_r1kh {
+ u8 bssid[ETH_ALEN];
+ u8 r1kh_id[FT_R1KH_ID_LEN];
+};
+
/**
* struct wpa_sm - Internal WPA state machine data
*/
@@ -31,10 +36,10 @@ struct wpa_sm {
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
-#endif /* CONFIG_IEEE80211W */
+ struct wpa_bigtk bigtk;
+ struct wpa_bigtk bigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -63,8 +68,21 @@ struct wpa_sm {
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey:1;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
+ int beacon_prot;
+ int ext_key_id; /* whether Extended Key ID is enabled */
+ int use_ext_key_id; /* whether Extended Key ID has been detected
+ * to be used */
+ int keyidx_active; /* Key ID for the active TK */
+
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -87,11 +105,19 @@ struct wpa_sm {
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
+ int sae_pwe; /* SAE PWE generation options */
+
+ unsigned int sae_pk:1; /* whether SAE-PK is used */
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
- u8 *ap_wpa_ie, *ap_rsn_ie;
- size_t ap_wpa_ie_len, ap_rsn_ie_len;
+ u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
+ size_t assoc_rsnxe_len;
+ u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
+ size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
@@ -135,6 +161,17 @@ struct wpa_sm {
u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
size_t assoc_resp_ies_len;
+#ifdef CONFIG_PASN
+ /*
+ * Currently, the WPA state machine stores the PMK-R1, PMK-R1-Name and
+ * R1KH-ID only for the current association. As PMK-R1 is required to
+ * perform PASN authentication with FT, store the R1KH-ID for previous
+ * associations, which would later be used to derive the PMK-R1 as part
+ * of the PASN authentication flow.
+ */
+ struct pasn_ft_r1kh *pasn_r1kh;
+ unsigned int n_pasn_r1kh;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_P2P
@@ -143,6 +180,11 @@ struct wpa_sm {
#ifdef CONFIG_TESTING_OPTIONS
struct wpabuf *test_assoc_ie;
+ int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
@@ -172,6 +214,7 @@ struct wpa_sm {
#ifdef CONFIG_DPP2
struct wpabuf *dpp_z;
+ int dpp_pfs;
#endif /* CONFIG_DPP2 */
};
@@ -197,11 +240,18 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code)
static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
WPA_ASSERT(sm->ctx->set_key);
return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
+}
+
+static inline void wpa_sm_reconnect(struct wpa_sm *sm)
+{
+ WPA_ASSERT(sm->ctx->reconnect);
+ sm->ctx->reconnect(sm->ctx->ctx);
}
static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
@@ -247,11 +297,13 @@ static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
- size_t pmk_len)
+ size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold, int akmp)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
- cache_id, pmk, pmk_len);
+ cache_id, pmk, pmk_len, pmk_lifetime,
+ pmk_reauth_threshold, akmp);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -346,6 +398,8 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len, const u8 *supp_oper_classes,
@@ -355,7 +409,9 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
aid, capability, supp_rates,
supp_rates_len, ht_capab,
- vht_capab, qosinfo, wmm,
+ vht_capab,
+ he_capab, he_capab_len,
+ qosinfo, wmm,
ext_capab, ext_capab_len,
supp_channels,
supp_channels_len,
@@ -409,6 +465,20 @@ static inline int wpa_sm_channel_info(struct wpa_sm *sm,
return sm->ctx->channel_info(sm->ctx->ctx, ci);
}
+static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
+{
+ if (sm->ctx->transition_disable)
+ sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
+}
+
+static inline void wpa_sm_store_ptk(struct wpa_sm *sm,
+ u8 *addr, int cipher,
+ u32 life_time, struct wpa_ptk *ptk)
+{
+ if (sm->ctx->store_ptk)
+ sm->ctx->store_ptk(sm->ctx->ctx, addr, cipher, life_time,
+ ptk);
+}
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.c b/contrib/wpa/src/rsn_supp/wpa_ie.c
index ae9f4ca241d8..3ba722f5ee85 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.c
@@ -105,6 +105,23 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
}
+u16 rsn_supp_capab(struct wpa_sm *sm)
+{
+ u16 capab = 0;
+
+ if (sm->mfp)
+ capab |= WPA_CAPABILITY_MFPC;
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int pairwise_cipher, int group_cipher,
int key_mgmt, int mgmt_group_cipher,
@@ -112,7 +129,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
{
u8 *pos;
struct rsn_ie_hdr *hdr;
- u16 capab;
u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
@@ -168,12 +184,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -216,16 +230,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
-#endif /* CONFIG_IEEE80211W */
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
if (sm->cur_pmksa) {
@@ -237,7 +242,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
@@ -250,7 +254,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
hdr->len = (pos - rsn_ie) - 2;
@@ -348,261 +351,41 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
}
-/**
- * wpa_parse_vendor_specific - Parse Vendor Specific IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- unsigned int oui;
-
- if (pos[1] < 4) {
- wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
- pos[1]);
- return 1;
- }
-
- oui = WPA_GET_BE24(&pos[2]);
- if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
- if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
- ie->wmm, ie->wmm_len);
- } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
- ie->wmm, ie->wmm_len);
- }
- }
- return 0;
-}
-
-
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
- ie->wpa_ie, ie->wpa_ie_len);
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
+ u8 *pos = rsnxe;
+ u16 capab = 0;
+ size_t flen;
+
+ if (wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sm->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
}
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
-
+ if (sm->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (sm->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (sm->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ if (rsnxe_len < 2 + flen)
+ return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
- ie->rsn_ie, ie->rsn_ie_len);
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
- pos[1] >= sizeof(struct rsn_mdie)) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
- ie->mdie, ie->mdie_len);
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
- pos[1] >= sizeof(struct rsn_ftie)) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
- ie->ftie, ie->ftie_len);
- } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
- if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
- ie->reassoc_deadline = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
- "in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
- } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
- ie->key_lifetime = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
- "in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
- "EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
- }
- } else if (*pos == WLAN_EID_LINK_ID) {
- if (pos[1] >= 18) {
- ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
- }
- } else if (*pos == WLAN_EID_EXT_CAPAB) {
- ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_SUPP_RATES) {
- ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
- ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_HT_CAP &&
- pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
- ie->ht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_VHT_AID) {
- if (pos[1] >= 2)
- ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
- } else if (*pos == WLAN_EID_VHT_CAP &&
- pos[1] >= sizeof(struct ieee80211_vht_capabilities))
- {
- ie->vht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
- ie->qosinfo = pos[2];
- } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
- ie->supp_channels = pos + 2;
- ie->supp_channels_len = pos[1];
- } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
- /*
- * The value of the Length field of the Supported
- * Operating Classes element is between 2 and 253.
- * Silently skip invalid elements to avoid interop
- * issues when trying to use the value.
- */
- if (pos[1] >= 2 && pos[1] <= 253) {
- ie->supp_oper_classes = pos + 2;
- ie->supp_oper_classes_len = pos[1];
- }
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
-
- ret = wpa_parse_vendor_specific(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
- return ret;
+ return pos - rsnxe;
}
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.h b/contrib/wpa/src/rsn_supp/wpa_ie.h
index 9d53973a9431..83a6727fe014 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.h
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.h
@@ -11,56 +11,8 @@
struct wpa_sm;
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *reassoc_deadline;
- const u8 *key_lifetime;
- const u8 *lnkid;
- size_t lnkid_len;
- const u8 *ext_capab;
- size_t ext_capab_len;
- const u8 *supp_rates;
- size_t supp_rates_len;
- const u8 *ext_supp_rates;
- size_t ext_supp_rates_len;
- const u8 *ht_capabilities;
- const u8 *vht_capabilities;
- const u8 *supp_channels;
- size_t supp_channels_len;
- const u8 *supp_oper_classes;
- size_t supp_oper_classes_len;
- u8 qosinfo;
- u16 aid;
- const u8 *wmm;
- size_t wmm_len;
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-};
-
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
+u16 rsn_supp_capab(struct wpa_sm *sm);
#endif /* WPA_IE_H */
diff --git a/contrib/wpa/src/tls/Makefile b/contrib/wpa/src/tls/Makefile
new file mode 100644
index 000000000000..c84fbe85938c
--- /dev/null
+++ b/contrib/wpa/src/tls/Makefile
@@ -0,0 +1,25 @@
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
+
+LIB_OBJS= \
+ asn1.o \
+ bignum.o \
+ pkcs1.o \
+ pkcs5.o \
+ pkcs8.o \
+ rsa.o \
+ tlsv1_client.o \
+ tlsv1_client_read.o \
+ tlsv1_client_write.o \
+ tlsv1_client_ocsp.o \
+ tlsv1_common.o \
+ tlsv1_cred.o \
+ tlsv1_record.o \
+ tlsv1_server.o \
+ tlsv1_server_read.o \
+ tlsv1_server_write.o \
+ x509v3.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/tls/asn1.c b/contrib/wpa/src/tls/asn1.c
index a08c2e1e3ed1..04d5320490f2 100644
--- a/contrib/wpa/src/tls/asn1.c
+++ b/contrib/wpa/src/tls/asn1.c
@@ -9,18 +9,99 @@
#include "includes.h"
#include "common.h"
+#include "utils/wpabuf.h"
#include "asn1.h"
-struct asn1_oid asn1_sha1_oid = {
+const struct asn1_oid asn1_sha1_oid = {
.oid = { 1, 3, 14, 3, 2, 26 },
.len = 6
};
-struct asn1_oid asn1_sha256_oid = {
+const struct asn1_oid asn1_sha256_oid = {
.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
.len = 9
};
+const struct asn1_oid asn1_ec_public_key_oid = {
+ .oid = { 1, 2, 840, 10045, 2, 1 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_prime256v1_oid = {
+ .oid = { 1, 2, 840, 10045, 3, 1, 7 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_secp384r1_oid = {
+ .oid = { 1, 3, 132, 0, 34 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_secp521r1_oid = {
+ .oid = { 1, 3, 132, 0, 35 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_brainpoolP256r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP384r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP512r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_pbkdf2_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 5, 12 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 9 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 10 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 11 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_dpp_config_params_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
+ .len = 10
+};
+
static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
{
@@ -48,6 +129,41 @@ static int asn1_valid_der(struct asn1_hdr *hdr)
return 1;
if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
return 0;
+ if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0)
+ return 0;
+
+ /* Check for allowed primitive/constructed values */
+ if (hdr->constructed &&
+ (hdr->tag == ASN1_TAG_BOOLEAN ||
+ hdr->tag == ASN1_TAG_INTEGER ||
+ hdr->tag == ASN1_TAG_NULL ||
+ hdr->tag == ASN1_TAG_OID ||
+ hdr->tag == ANS1_TAG_RELATIVE_OID ||
+ hdr->tag == ASN1_TAG_REAL ||
+ hdr->tag == ASN1_TAG_ENUMERATED ||
+ hdr->tag == ASN1_TAG_BITSTRING ||
+ hdr->tag == ASN1_TAG_OCTETSTRING ||
+ hdr->tag == ASN1_TAG_NUMERICSTRING ||
+ hdr->tag == ASN1_TAG_PRINTABLESTRING ||
+ hdr->tag == ASN1_TAG_T61STRING ||
+ hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
+ hdr->tag == ASN1_TAG_VISIBLESTRING ||
+ hdr->tag == ASN1_TAG_IA5STRING ||
+ hdr->tag == ASN1_TAG_GRAPHICSTRING ||
+ hdr->tag == ASN1_TAG_GENERALSTRING ||
+ hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
+ hdr->tag == ASN1_TAG_UTF8STRING ||
+ hdr->tag == ASN1_TAG_BMPSTRING ||
+ hdr->tag == ASN1_TAG_CHARACTERSTRING ||
+ hdr->tag == ASN1_TAG_UTCTIME ||
+ hdr->tag == ASN1_TAG_GENERALIZEDTIME ||
+ hdr->tag == ASN1_TAG_TIME))
+ return 0;
+ if (!hdr->constructed &&
+ (hdr->tag == ASN1_TAG_SEQUENCE ||
+ hdr->tag == ASN1_TAG_SET))
+ return 0;
+
return 1;
}
@@ -70,18 +186,35 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
hdr->constructed = !!(hdr->identifier & (1 << 5));
if ((hdr->identifier & 0x1f) == 0x1f) {
+ size_t ext_len = 0;
+
hdr->tag = 0;
+ if (pos == end || (*pos & 0x7f) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)");
+ return -1;
+ }
do {
if (pos >= end) {
wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
"underflow");
return -1;
}
+ ext_len++;
tmp = *pos++;
wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
"0x%02x", tmp);
hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
} while (tmp & 0x80);
+ wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)",
+ hdr->tag, ext_len);
+ if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) ||
+ ext_len * 7 > sizeof(hdr->tag) * 8) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)",
+ hdr->tag, ext_len);
+ return -1;
+ }
} else
hdr->tag = hdr->identifier & 0x1f;
@@ -98,6 +231,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
}
tmp &= 0x7f; /* number of subsequent octets */
hdr->length = 0;
+ if (tmp == 0 || pos == end || *pos == 0) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Definite long form of the length does not start with a nonzero value");
+ return -1;
+ }
if (tmp > 4) {
wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
return -1;
@@ -110,6 +248,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
}
hdr->length = (hdr->length << 8) | *pos++;
}
+ if (hdr->length < 128) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Definite long form of the length used with too short length");
+ return -1;
+ }
} else {
/* Short form - length 0..127 in one octet */
hdr->length = tmp;
@@ -122,7 +265,25 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
hdr->payload = pos;
- return asn1_valid_der(hdr) ? 0 : -1;
+ if (!asn1_valid_der(hdr)) {
+ asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: ");
+ return -1;
+ }
+ return 0;
+}
+
+
+void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title)
+{
+ wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x",
+ title, hdr->class, hdr->constructed, hdr->tag);
+}
+
+
+void asn1_unexpected(const struct asn1_hdr *hdr, const char *title)
+{
+ wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x",
+ title, hdr->class, hdr->constructed, hdr->tag);
}
@@ -175,12 +336,9 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
{
struct asn1_hdr hdr;
- if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
- return -1;
-
- if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
- wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
- "tag 0x%x", hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
+ !asn1_is_oid(&hdr)) {
+ asn1_unexpected(&hdr, "ASN.1: Expected OID");
return -1;
}
@@ -270,3 +428,223 @@ int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
return 1;
}
+
+
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
+{
+ struct asn1_hdr hdr;
+ size_t left;
+ const u8 *pos;
+ int value;
+
+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "ASN.1: Expected INTEGER");
+ return -1;
+ }
+
+ *next = hdr.payload + hdr.length;
+ pos = hdr.payload;
+ left = hdr.length;
+ if (left > sizeof(value)) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
+ hdr.length);
+ return -1;
+ }
+ value = 0;
+ while (left) {
+ value <<= 8;
+ value |= *pos++;
+ left--;
+ }
+
+ *integer = value;
+ return 0;
+}
+
+
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next)
+{
+ if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) {
+ asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE");
+ return -1;
+ }
+
+ if (next)
+ *next = hdr->payload + hdr->length;
+ return 0;
+}
+
+
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next)
+{
+ const u8 *pos = buf, *end = buf + len;
+ struct asn1_hdr hdr;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
+ return -1;
+
+ if (params && params_len) {
+ *params = pos;
+ *params_len = hdr.payload + hdr.length - pos;
+ }
+
+ return 0;
+}
+
+
+void asn1_put_integer(struct wpabuf *buf, int val)
+{
+ u8 bin[4];
+ int zeros;
+
+ WPA_PUT_BE32(bin, val);
+ zeros = 0;
+ while (zeros < 3 && bin[zeros] == 0)
+ zeros++;
+ wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
+ wpabuf_put_u8(buf, 4 - zeros);
+ wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
+}
+
+
+static void asn1_put_len(struct wpabuf *buf, size_t len)
+{
+ if (len <= 0x7f) {
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xff) {
+ wpabuf_put_u8(buf, 0x80 | 1);
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xffff) {
+ wpabuf_put_u8(buf, 0x80 | 2);
+ wpabuf_put_be16(buf, len);
+ } else if (len <= 0xffffff) {
+ wpabuf_put_u8(buf, 0x80 | 3);
+ wpabuf_put_be24(buf, len);
+ } else {
+ wpabuf_put_u8(buf, 0x80 | 4);
+ wpabuf_put_be32(buf, len);
+ }
+}
+
+
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
+{
+ wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
+ asn1_put_len(buf, wpabuf_len(val));
+ wpabuf_put_buf(buf, val);
+}
+
+
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
+{
+ u8 *len;
+ size_t i;
+
+ if (oid->len < 2)
+ return;
+ wpabuf_put_u8(buf, ASN1_TAG_OID);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
+ for (i = 2; i < oid->len; i++) {
+ unsigned long val = oid->oid[i];
+ u8 bytes[8];
+ int idx = 0;
+
+ while (val) {
+ bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
+ idx++;
+ val >>= 7;
+ }
+ if (idx == 0) {
+ bytes[idx] = 0;
+ idx = 1;
+ }
+ while (idx > 0) {
+ idx--;
+ wpabuf_put_u8(buf, bytes[idx]);
+ }
+ }
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len)
+{
+ wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
+ asn1_put_len(buf, len);
+}
+
+
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_utf8string(struct wpabuf *buf, const char *val)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
+ os_strlen(val));
+ wpabuf_put_str(buf, val);
+}
+
+
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+
+ len = 100;
+ if (params)
+ len += wpabuf_len(params);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+ asn1_put_oid(buf, oid);
+ if (params)
+ wpabuf_put_buf(buf, params);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
+{
+ struct wpabuf *res;
+
+ if (!buf)
+ return NULL;
+ res = wpabuf_alloc(10 + wpabuf_len(buf));
+ if (res) {
+ asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
+ wpabuf_put_buf(res, buf);
+ }
+ wpabuf_clear_free(buf);
+ return res;
+}
diff --git a/contrib/wpa/src/tls/asn1.h b/contrib/wpa/src/tls/asn1.h
index 6bd7df565dba..a4d1be473521 100644
--- a/contrib/wpa/src/tls/asn1.h
+++ b/contrib/wpa/src/tls/asn1.h
@@ -23,11 +23,12 @@
#define ASN1_TAG_EMBEDDED_PDV 0x0B /* not yet parsed */
#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */
#define ANS1_TAG_RELATIVE_OID 0x0D
+#define ASN1_TAG_TIME 0x0E
#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
#define ASN1_TAG_SET 0x11
#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */
#define ASN1_TAG_PRINTABLESTRING 0x13
-#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */
+#define ASN1_TAG_T61STRING 0x14 /* not yet parsed */
#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */
#define ASN1_TAG_IA5STRING 0x16
#define ASN1_TAG_UTCTIME 0x17
@@ -59,14 +60,153 @@ struct asn1_oid {
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
+void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title);
+void asn1_unexpected(const struct asn1_hdr *hdr, const char *title);
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
const u8 **next);
void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next);
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next);
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next);
+void asn1_put_integer(struct wpabuf *buf, int val);
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val);
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid);
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len);
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_utf8string(struct wpabuf *buf, const char *val);
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params);
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag);
-extern struct asn1_oid asn1_sha1_oid;
-extern struct asn1_oid asn1_sha256_oid;
+static inline bool asn1_is_oid(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_OID;
+}
+
+static inline bool asn1_is_boolean(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_BOOLEAN;
+}
+
+static inline bool asn1_is_integer(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_INTEGER;
+}
+
+static inline bool asn1_is_enumerated(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_ENUMERATED;
+}
+
+static inline bool asn1_is_sequence(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_SEQUENCE;
+}
+
+static inline bool asn1_is_set(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_SET;
+}
+
+static inline bool asn1_is_octetstring(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_OCTETSTRING;
+}
+
+static inline bool asn1_is_bitstring(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_BITSTRING;
+}
+
+static inline bool asn1_is_utctime(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_UTCTIME;
+}
+
+static inline bool asn1_is_generalizedtime(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_GENERALIZEDTIME;
+}
+
+static inline bool asn1_is_string_type(const struct asn1_hdr *hdr)
+{
+ if (hdr->class != ASN1_CLASS_UNIVERSAL || hdr->constructed)
+ return false;
+ return hdr->tag == ASN1_TAG_UTF8STRING ||
+ hdr->tag == ASN1_TAG_NUMERICSTRING ||
+ hdr->tag == ASN1_TAG_PRINTABLESTRING ||
+ hdr->tag == ASN1_TAG_T61STRING ||
+ hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
+ hdr->tag == ASN1_TAG_IA5STRING ||
+ hdr->tag == ASN1_TAG_GRAPHICSTRING ||
+ hdr->tag == ASN1_TAG_VISIBLESTRING ||
+ hdr->tag == ASN1_TAG_GENERALSTRING ||
+ hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
+ hdr->tag == ASN1_TAG_CHARACTERSTRING ||
+ hdr->tag == ASN1_TAG_BMPSTRING;
+}
+
+static inline bool asn1_is_bmpstring(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_BMPSTRING;
+}
+
+static inline bool asn1_is_utf8string(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_UTF8STRING;
+}
+
+static inline bool asn1_is_null(const struct asn1_hdr *hdr)
+{
+ return hdr->class == ASN1_CLASS_UNIVERSAL &&
+ hdr->tag == ASN1_TAG_NULL;
+}
+
+static inline bool asn1_is_cs_tag(const struct asn1_hdr *hdr, unsigned int tag)
+{
+ return hdr->class == ASN1_CLASS_CONTEXT_SPECIFIC &&
+ hdr->tag == tag;
+}
+
+extern const struct asn1_oid asn1_sha1_oid;
+extern const struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_ec_public_key_oid;
+extern const struct asn1_oid asn1_prime256v1_oid;
+extern const struct asn1_oid asn1_secp384r1_oid;
+extern const struct asn1_oid asn1_secp521r1_oid;
+extern const struct asn1_oid asn1_brainpoolP256r1_oid;
+extern const struct asn1_oid asn1_brainpoolP384r1_oid;
+extern const struct asn1_oid asn1_brainpoolP512r1_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_pbkdf2_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid;
+extern const struct asn1_oid asn1_dpp_config_params_oid;
+extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid;
#endif /* ASN1_H */
diff --git a/contrib/wpa/src/tls/pkcs1.c b/contrib/wpa/src/tls/pkcs1.c
index 141ac50df401..49e439d02768 100644
--- a/contrib/wpa/src/tls/pkcs1.c
+++ b/contrib/wpa/src/tls/pkcs1.c
@@ -157,6 +157,7 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
plain[0] != 0x00 || plain[1] != 0x01) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
@@ -165,6 +166,7 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
if (plain[2] != 0xff) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
"PS (BT=01)");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
while (pos < plain + len && *pos == 0xff)
@@ -174,12 +176,14 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
"padding");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure (2)");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
pos++;
@@ -232,14 +236,14 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
*
*/
if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #1: Expected SEQUENCE (DigestInfo) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #1: Expected SEQUENCE (DigestInfo)");
os_free(decrypted);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestInfo",
+ hdr.payload, hdr.length);
pos = hdr.payload;
end = pos + hdr.length;
@@ -253,14 +257,14 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier)");
os_free(decrypted);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestAlgorithmIdentifier",
+ hdr.payload, hdr.length);
da_end = hdr.payload + hdr.length;
if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
@@ -269,6 +273,23 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
os_free(decrypted);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Digest algorithm parameters",
+ next, da_end - next);
+
+ /*
+ * RFC 5754: The correct encoding for the SHA2 algorithms would be to
+ * omit the parameters, but there are implementation that encode these
+ * as a NULL element. Allow these two cases and reject anything else.
+ */
+ if (da_end > next &&
+ (asn1_get_next(next, da_end - next, &hdr) < 0 ||
+ !asn1_is_null(&hdr) ||
+ hdr.payload + hdr.length != da_end)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Unexpected digest algorithm parameters");
+ os_free(decrypted);
+ return -1;
+ }
if (!asn1_oid_equal(&oid, hash_alg)) {
char txt[100], txt2[100];
@@ -283,14 +304,11 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
/* Digest ::= OCTET STRING */
pos = da_end;
- end = decrypted + decrypted_len;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #1: Expected OCTETSTRING (Digest) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #1: Expected OCTETSTRING (Digest)");
os_free(decrypted);
return -1;
}
@@ -306,13 +324,14 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
os_free(decrypted);
- if (hdr.payload + hdr.length != end) {
+ if (hdr.payload + hdr.length != decrypted + decrypted_len) {
wpa_printf(MSG_INFO,
"PKCS #1: Extra data after signature - reject");
wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data",
hdr.payload + hdr.length,
- end - hdr.payload - hdr.length);
+ decrypted + decrypted_len - hdr.payload -
+ hdr.length);
return -1;
}
diff --git a/contrib/wpa/src/tls/pkcs5.c b/contrib/wpa/src/tls/pkcs5.c
index a2ad83b8a898..7bef89b4fdf5 100644
--- a/contrib/wpa/src/tls/pkcs5.c
+++ b/contrib/wpa/src/tls/pkcs5.c
@@ -107,22 +107,18 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
*/
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected SEQUENCE (PBES2-params) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected SEQUENCE (PBES2-params)");
return -1;
}
pos = hdr.payload;
end = hdr.payload + hdr.length;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected SEQUENCE (keyDerivationFunc) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected SEQUENCE (keyDerivationFunc)");
return -1;
}
@@ -161,11 +157,9 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected SEQUENCE (PBKDF2-params) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected SEQUENCE (PBKDF2-params)");
return -1;
}
@@ -174,12 +168,10 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
/* For now, only support the salt CHOICE specified (OCTET STRING) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING ||
+ !asn1_is_octetstring(&hdr) ||
hdr.length > sizeof(params->salt)) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected OCTET STRING (salt.specified) - found class %d tag 0x%x size %d",
- hdr.class, hdr.tag, hdr.length);
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected OCTET STRING (salt.specified)");
return -1;
}
pos = hdr.payload + hdr.length;
@@ -188,11 +180,8 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len);
/* iterationCount INTEGER */
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected INTEGER - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER");
return -1;
}
if (hdr.length == 1) {
@@ -222,11 +211,9 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
/* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected SEQUENCE (encryptionScheme) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected SEQUENCE (encryptionScheme)");
return -1;
}
@@ -258,12 +245,9 @@ static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
* specifying the initialization vector for CBC mode.
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING ||
- hdr.length != 8) {
- wpa_printf(MSG_DEBUG,
- "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV) - found class %d tag 0x%x size %d",
- hdr.class, hdr.tag, hdr.length);
+ !asn1_is_octetstring(&hdr) || hdr.length != 8) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV)");
return -1;
}
os_memcpy(params->iv, hdr.payload, hdr.length);
@@ -323,11 +307,9 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
*/
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
- "(PBEParameter) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected SEQUENCE (PBEParameter)");
return -1;
}
pos = hdr.payload;
@@ -335,12 +317,9 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
/* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING ||
- hdr.length > sizeof(params->salt)) {
- wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
- "(salt) - found class %d tag 0x%x size %d",
- hdr.class, hdr.tag, hdr.length);
+ !asn1_is_octetstring(&hdr) || hdr.length > sizeof(params->salt)) {
+ asn1_unexpected(&hdr,
+ "PKCS #5: Expected OCTETSTRING SIZE(8) (salt)");
return -1;
}
pos = hdr.payload + hdr.length;
@@ -351,9 +330,8 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
/* iterationCount INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
- "class %d tag 0x%x", hdr.class, hdr.tag);
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER");
return -1;
}
if (hdr.length == 1)
diff --git a/contrib/wpa/src/tls/pkcs8.c b/contrib/wpa/src/tls/pkcs8.c
index 52e43a4403b9..75bbd120c028 100644
--- a/contrib/wpa/src/tls/pkcs8.c
+++ b/contrib/wpa/src/tls/pkcs8.c
@@ -27,22 +27,17 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
/* PKCS #8, Chapter 6 */
/* PrivateKeyInfo ::= SEQUENCE */
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
- "header (SEQUENCE); assume PKCS #8 not used");
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Does not start with PKCS #8 header (SEQUENCE)");
return NULL;
}
pos = hdr.payload;
end = pos + hdr.length;
/* version Version (Version ::= INTEGER) */
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
- "class %d tag 0x%x; assume PKCS #8 not used",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #8: Expected INTEGER");
return NULL;
}
@@ -68,13 +63,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
* (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
- "(AlgorithmIdentifier) - found class %d tag 0x%x; "
- "assume PKCS #8 not used",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume PKCS #8 not used");
return NULL;
}
@@ -104,11 +95,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
- "(privateKey) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Expected OCTETSTRING (privateKey)");
return NULL;
}
wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
@@ -139,12 +128,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
* EncryptedData ::= OCTET STRING
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
- "header (SEQUENCE); assume encrypted PKCS #8 not "
- "used");
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Does not start with PKCS #8 header (SEQUENCE); assume encrypted PKCS #8 not used");
return NULL;
}
pos = hdr.payload;
@@ -152,12 +138,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
- "(AlgorithmIdentifier) - found class %d tag 0x%x; "
- "assume encrypted PKCS #8 not used",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume encrypted PKCS #8 not used");
return NULL;
}
enc_alg = hdr.payload;
@@ -166,11 +149,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
/* encryptedData EncryptedData */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
- "(encryptedData) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #8: Expected OCTETSTRING (encryptedData)");
return NULL;
}
diff --git a/contrib/wpa/src/tls/rsa.c b/contrib/wpa/src/tls/rsa.c
index 3525eb9919db..56ae7d7795aa 100644
--- a/contrib/wpa/src/tls/rsa.c
+++ b/contrib/wpa/src/tls/rsa.c
@@ -37,9 +37,8 @@ static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
return NULL;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
- "tag 0x%x", hdr.class, hdr.tag);
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "RSA: Expected INTEGER");
return NULL;
}
@@ -84,12 +83,8 @@ crypto_rsa_import_public_key(const u8 *buf, size_t len)
* }
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
- "(public key) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "RSA: Expected SEQUENCE (public key)");
goto error;
}
pos = hdr.payload;
@@ -191,12 +186,8 @@ crypto_rsa_import_private_key(const u8 *buf, size_t len)
*
* Version ::= INTEGER -- shall be 0 for this version of the standard
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
- "(public key) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "RSA: Expected SEQUENCE (public key)");
goto error;
}
pos = hdr.payload;
@@ -285,7 +276,7 @@ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
if (use_private) {
/*
- * Decrypt (or sign) using Chinese remainer theorem to speed
+ * Decrypt (or sign) using Chinese remainder theorem to speed
* up calculation. This is equivalent to tmp = tmp^d mod n
* (which would require more CPU to calculate directly).
*
diff --git a/contrib/wpa/src/tls/tlsv1_client.c b/contrib/wpa/src/tls/tlsv1_client.c
index a147a54a3d10..486da16fd3c9 100644
--- a/contrib/wpa/src/tls/tlsv1_client.c
+++ b/contrib/wpa/src/tls/tlsv1_client.c
@@ -38,9 +38,33 @@ void tlsv1_client_free_dh(struct tlsv1_client *conn)
}
-int tls_derive_pre_master_secret(u8 *pre_master_secret)
+u16 tls_client_highest_ver(struct tlsv1_client *conn)
{
- WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
+ u16 tls_version = TLS_VERSION;
+
+ /* Pick the highest locally enabled TLS version */
+#ifdef CONFIG_TLSV12
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+ tls_version == TLS_VERSION_1_2)
+ tls_version = TLS_VERSION_1_1;
+#endif /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+ tls_version == TLS_VERSION_1_1)
+ tls_version = TLS_VERSION_1;
+#endif /* CONFIG_TLSV11 */
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+ tls_version == TLS_VERSION_1)
+ return 0;
+
+ return tls_version;
+}
+
+
+int tls_derive_pre_master_secret(struct tlsv1_client *conn,
+ u8 *pre_master_secret)
+{
+ WPA_PUT_BE16(pre_master_secret, tls_client_highest_ver(conn));
if (os_get_random(pre_master_secret + 2,
TLS_PRE_MASTER_SECRET_LEN - 2))
return -1;
@@ -844,6 +868,7 @@ int tlsv1_client_set_cred(struct tlsv1_client *conn,
void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags)
{
conn->flags = flags;
+ conn->rl.tls_version = tls_client_highest_ver(conn);
}
diff --git a/contrib/wpa/src/tls/tlsv1_client_i.h b/contrib/wpa/src/tls/tlsv1_client_i.h
index 12ec8df6c3ac..ccb2e1580849 100644
--- a/contrib/wpa/src/tls/tlsv1_client_i.h
+++ b/contrib/wpa/src/tls/tlsv1_client_i.h
@@ -78,7 +78,9 @@ struct tlsv1_client {
void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
void tlsv1_client_free_dh(struct tlsv1_client *conn);
-int tls_derive_pre_master_secret(u8 *pre_master_secret);
+u16 tls_client_highest_ver(struct tlsv1_client *conn);
+int tls_derive_pre_master_secret(struct tlsv1_client *conn,
+ u8 *pre_master_secret);
int tls_derive_keys(struct tlsv1_client *conn,
const u8 *pre_master_secret, size_t pre_master_secret_len);
u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
diff --git a/contrib/wpa/src/tls/tlsv1_client_ocsp.c b/contrib/wpa/src/tls/tlsv1_client_ocsp.c
index 1d7b68ca286e..128f4b5b9e7b 100644
--- a/contrib/wpa/src/tls/tlsv1_client_ocsp.c
+++ b/contrib/wpa/src/tls/tlsv1_client_ocsp.c
@@ -138,12 +138,8 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
*/
/* CertID ::= SEQUENCE */
- if (asn1_get_next(resp, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (CertID) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "OCSP: Expected SEQUENCE (CertID)");
return -1;
}
pos = hdr.payload;
@@ -163,11 +159,9 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
/* issuerNameHash OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected OCTET STRING (issuerNameHash) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected OCTET STRING (issuerNameHash)");
return -1;
}
name_hash = hdr.payload;
@@ -190,11 +184,9 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
/* issuerKeyHash OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected OCTET STRING (issuerKeyHash) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected OCTET STRING (issuerKeyHash)");
return -1;
}
key_hash = hdr.payload;
@@ -214,11 +206,10 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
/* serialNumber CertificateSerialNumber ::= INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER ||
+ !asn1_is_integer(&hdr) ||
hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
- wpa_printf(MSG_DEBUG, "OCSP: No INTEGER tag found for serialNumber; class=%d tag=0x%x length=%u",
- hdr.class, hdr.tag, hdr.length);
+ asn1_unexpected(&hdr,
+ "OCSP: No INTEGER tag found for serialNumber");
return -1;
}
serial_number = hdr.payload;
@@ -240,12 +231,16 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
pos = end;
end = resp + len;
- /* certStatus CertStatus ::= CHOICE */
+ /* certStatus CertStatus ::= CHOICE
+ *
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected CHOICE (CertStatus) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ asn1_unexpected(&hdr, "OCSP: Expected CHOICE (CertStatus)");
return -1;
}
cert_status = hdr.tag;
@@ -257,8 +252,7 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
os_get_time(&now);
/* thisUpdate GeneralizedTime */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ !asn1_is_generalizedtime(&hdr) ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag, &update) < 0) {
wpa_printf(MSG_DEBUG, "OCSP: Failed to parse thisUpdate");
return -1;
@@ -275,12 +269,11 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
if (pos < end) {
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
- if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && hdr.tag == 0) {
+ if (asn1_is_cs_tag(&hdr, 0) && hdr.constructed) {
const u8 *next = hdr.payload + hdr.length;
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ !asn1_is_generalizedtime(&hdr) ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&update) < 0) {
wpa_printf(MSG_DEBUG,
@@ -329,11 +322,9 @@ tls_process_ocsp_responses(struct tlsv1_client *conn,
while (pos < end) {
/* SingleResponse ::= SEQUENCE */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (SingleResponse) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (SingleResponse)");
return TLS_OCSP_INVALID;
}
if (tls_process_ocsp_single_response(conn, cert, issuer,
@@ -381,12 +372,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
*/
- if (asn1_get_next(resp, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (BasicOCSPResponse) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (BasicOCSPResponse)");
return TLS_OCSP_INVALID;
}
pos = hdr.payload;
@@ -394,11 +382,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
/* ResponseData ::= SEQUENCE */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (ResponseData) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (ResponseData)");
return TLS_OCSP_INVALID;
}
resp_data = hdr.payload;
@@ -413,11 +399,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
/* signature BIT STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_BITSTRING) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected BITSTRING (signature) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_bitstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected BITSTRING (signature)");
return TLS_OCSP_INVALID;
}
if (hdr.length < 1)
@@ -439,11 +423,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
/* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL */
if (pos < end) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected [0] EXPLICIT (certs) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !hdr.constructed || !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected [0] EXPLICIT (certs)");
return TLS_OCSP_INVALID;
}
wpa_hexdump(MSG_MSGDUMP, "OCSP: certs",
@@ -454,11 +436,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
struct x509_certificate *cert;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (Certificate) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (Certificate)");
goto fail;
}
@@ -491,16 +471,12 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
* version [0] EXPLICIT Version DEFAULT v1
* Version ::= INTEGER { v1(0) }
*/
- if (asn1_get_next(pos, end - pos, &hdr) < 0 &&
- hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
- hdr.tag == 0) {
+ if (asn1_get_next(pos, end - pos, &hdr) == 0 && hdr.constructed &&
+ asn1_is_cs_tag(&hdr, 0)) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER ||
- hdr.length != 1) {
- wpa_printf(MSG_DEBUG,
- "OCSP: No INTEGER (len=1) tag found for version field - found class %d tag 0x%x length %d",
- hdr.class, hdr.tag, hdr.length);
+ !asn1_is_integer(&hdr) || hdr.length != 1) {
+ asn1_unexpected(&hdr,
+ "OCSP: No INTEGER (len=1) tag found for version field");
goto fail;
}
wpa_printf(MSG_DEBUG, "OCSP: ResponseData version %u",
@@ -524,9 +500,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected CHOICE (ResponderID) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ asn1_unexpected(&hdr, "OCSP: Expected CHOICE (ResponderID)");
goto fail;
}
@@ -539,11 +513,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
} else if (hdr.tag == 2) {
/* KeyHash ::= OCTET STRING */
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected OCTET STRING (KeyHash) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected OCTET STRING (KeyHash)");
goto fail;
}
key_hash = hdr.payload;
@@ -564,8 +536,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
/* producedAt GeneralizedTime */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ !asn1_is_generalizedtime(&hdr) ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&produced_at) < 0) {
wpa_printf(MSG_DEBUG, "OCSP: Failed to parse producedAt");
@@ -577,11 +548,9 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn,
/* responses SEQUENCE OF SingleResponse */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (responses) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (responses)");
goto fail;
}
responses = hdr.payload;
@@ -697,12 +666,9 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
*/
- if (asn1_get_next(resp, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (OCSPResponse) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (OCSPResponse)");
return TLS_OCSP_INVALID;
}
pos = hdr.payload;
@@ -710,12 +676,9 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
/* OCSPResponseStatus ::= ENUMERATED */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_ENUMERATED ||
- hdr.length != 1) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected ENUMERATED (responseStatus) - found class %d tag 0x%x length %u",
- hdr.class, hdr.tag, hdr.length);
+ !asn1_is_enumerated(&hdr) || hdr.length != 1) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected ENUMERATED (responseStatus)");
return TLS_OCSP_INVALID;
}
resp_status = hdr.payload[0];
@@ -730,12 +693,10 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
if (pos == end)
return TLS_OCSP_NO_RESPONSE;
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected [0] EXPLICIT (responseBytes) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected [0] EXPLICIT (responseBytes)");
return TLS_OCSP_INVALID;
}
@@ -746,11 +707,9 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
*/
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected SEQUENCE (ResponseBytes) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "OCSP: Expected SEQUENCE (ResponseBytes)");
return TLS_OCSP_INVALID;
}
pos = hdr.payload;
@@ -771,11 +730,8 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
/* response OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "OCSP: Expected OCTET STRING (response) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr, "OCSP: Expected OCTET STRING (response)");
return TLS_OCSP_INVALID;
}
diff --git a/contrib/wpa/src/tls/tlsv1_client_read.c b/contrib/wpa/src/tls/tlsv1_client_read.c
index 80874e59d1de..3825a7380dd5 100644
--- a/contrib/wpa/src/tls/tlsv1_client_read.c
+++ b/contrib/wpa/src/tls/tlsv1_client_read.c
@@ -312,6 +312,14 @@ static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
x509_name_string(&cert->subject, subject, sizeof(subject));
ev.peer_cert.subject = subject;
+ if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) {
+ if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT)
+ ev.peer_cert.tod = 1;
+ else if (cert->certificate_policy &
+ X509_EXT_CERT_POLICY_TOD_TOFU)
+ ev.peer_cert.tod = 2;
+ }
+
conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert_buf);
}
@@ -532,7 +540,7 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
}
} else if (conn->cred && conn->cred->cert_probe) {
wpa_printf(MSG_DEBUG,
- "TLSv1: Reject server certificate on probe-only rune");
+ "TLSv1: Reject server certificate on probe-only run");
if (conn->event_cb) {
union tls_event_data ev;
char buf[128];
diff --git a/contrib/wpa/src/tls/tlsv1_client_write.c b/contrib/wpa/src/tls/tlsv1_client_write.c
index 4a1147b69e76..9b12618aaf06 100644
--- a/contrib/wpa/src/tls/tlsv1_client_write.c
+++ b/contrib/wpa/src/tls/tlsv1_client_write.c
@@ -48,21 +48,9 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
struct os_time now;
size_t len, i;
u8 *ext_start;
- u16 tls_version = TLS_VERSION;
+ u16 tls_version = tls_client_highest_ver(conn);
- /* Pick the highest locally enabled TLS version */
-#ifdef CONFIG_TLSV12
- if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
- tls_version == TLS_VERSION_1_2)
- tls_version = TLS_VERSION_1_1;
-#endif /* CONFIG_TLSV12 */
-#ifdef CONFIG_TLSV11
- if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
- tls_version == TLS_VERSION_1_1)
- tls_version = TLS_VERSION_1;
-#endif /* CONFIG_TLSV11 */
- if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
- tls_version == TLS_VERSION_1) {
+ if (!tls_version) {
wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
return NULL;
}
@@ -474,7 +462,7 @@ static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
size_t clen;
int res;
- if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+ if (tls_derive_pre_master_secret(conn, pre_master_secret) < 0 ||
tls_derive_keys(conn, pre_master_secret,
TLS_PRE_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
diff --git a/contrib/wpa/src/tls/tlsv1_cred.c b/contrib/wpa/src/tls/tlsv1_cred.c
index 842e5dd728c7..1310f4e10e8e 100644
--- a/contrib/wpa/src/tls/tlsv1_cred.c
+++ b/contrib/wpa/src/tls/tlsv1_cred.c
@@ -130,7 +130,7 @@ static int tlsv1_add_cert(struct x509_certificate **chain,
return -1;
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
"certificate");
@@ -293,7 +293,7 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
}
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, NULL);
@@ -321,7 +321,7 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
if (!end)
return NULL;
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, passwd);
@@ -455,12 +455,8 @@ static int pkcs12_certbag(struct tlsv1_credentials *cred,
* }
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (CertBag) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #12: Expected SEQUENCE (CertBag)");
return -1;
}
@@ -482,21 +478,17 @@ static int pkcs12_certbag(struct tlsv1_credentials *cred,
obuf);
}
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected [0] EXPLICIT (certValue) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected [0] EXPLICIT (certValue)");
return -1;
}
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected OCTET STRING (x509Certificate) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected OCTET STRING (x509Certificate)");
return -1;
}
@@ -534,11 +526,9 @@ static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
* }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_BMPSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected BMPSTRING (friendlyName) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_bmpstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected BMPSTRING (friendlyName)");
return 0;
}
wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
@@ -561,11 +551,9 @@ static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
* }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected OCTET STRING (localKeyID) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected OCTET STRING (localKeyID)");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
@@ -596,12 +584,8 @@ static int pkcs12_parse_attr(const u8 *pos, size_t len)
asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SET) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SET (attrValues) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #12: Expected SET (attrValues)");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
@@ -641,12 +625,10 @@ static int pkcs12_safebag(struct tlsv1_credentials *cred,
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected [0] EXPLICIT (bagValue) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected [0] EXPLICIT (bagValue)");
return 0;
}
value = hdr.payload;
@@ -657,11 +639,9 @@ static int pkcs12_safebag(struct tlsv1_credentials *cred,
if (pos < end) {
/* bagAttributes SET OF PKCS12Attribute OPTIONAL */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SET) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SET (bagAttributes) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SET (bagAttributes)");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
@@ -672,11 +652,9 @@ static int pkcs12_safebag(struct tlsv1_credentials *cred,
while (pos < end) {
/* PKCS12Attribute ::= SEQUENCE */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (PKCS12Attribute) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (PKCS12Attribute)");
return -1;
}
if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
@@ -705,12 +683,9 @@ static int pkcs12_safecontents(struct tlsv1_credentials *cred,
const u8 *pos, *end;
/* SafeContents ::= SEQUENCE OF SafeBag */
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (SafeContents) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (SafeContents)");
return -1;
}
pos = hdr.payload;
@@ -726,11 +701,9 @@ static int pkcs12_safecontents(struct tlsv1_credentials *cred,
while (pos < end) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (SafeBag) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (SafeBag)");
return -1;
}
if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
@@ -750,11 +723,8 @@ static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
/* Data ::= OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr, "PKCS #12: Expected OCTET STRING (Data)");
return -1;
}
@@ -782,21 +752,17 @@ static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
* encryptedContentInfo EncryptedContentInfo }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (EncryptedData) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (EncryptedData)");
return 0;
}
pos = hdr.payload;
/* Version ::= INTEGER */
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: No INTEGER tag found for version");
return -1;
}
if (hdr.length != 1 || hdr.payload[0] != 0) {
@@ -815,11 +781,9 @@ static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (EncryptedContentInfo) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (EncryptedContentInfo)");
return -1;
}
@@ -845,22 +809,19 @@ static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
/* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier)");
return -1;
}
enc_alg = hdr.payload;
enc_alg_len = hdr.length;
pos = hdr.payload + hdr.length;
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected [0] IMPLICIT (encryptedContent) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected [0] IMPLICIT (encryptedContent)");
return -1;
}
@@ -900,12 +861,10 @@ static int pkcs12_parse_content(struct tlsv1_credentials *cred,
asn1_oid_to_str(&oid, txt, sizeof(txt));
wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected [0] EXPLICIT (content)");
return 0;
}
pos = hdr.payload;
@@ -938,23 +897,18 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
* }
*/
- if (asn1_get_next(key, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (PFX) - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ if (asn1_get_next(key, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (PFX); assume PKCS #12 not used");
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: No INTEGER tag found for version");
return -1;
}
if (hdr.length != 1 || hdr.payload[0] != 3) {
@@ -970,11 +924,9 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (authSafe); assume PKCS #12 not used");
return -1;
}
@@ -995,12 +947,10 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
return -1;
}
- if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
- hdr.tag != 0) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+ !asn1_is_cs_tag(&hdr, 0)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected [0] EXPLICIT (content); assume PKCS #12 not used");
return -1;
}
@@ -1008,11 +958,9 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
/* Data ::= OCTET STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected OCTET STRING (Data); assume PKCS #12 not used");
return -1;
}
@@ -1026,11 +974,9 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
hdr.payload, hdr.length);
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE within Data content - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE within Data content; assume PKCS #12 not used");
return -1;
}
@@ -1039,11 +985,9 @@ static int pkcs12_parse(struct tlsv1_credentials *cred,
while (end > pos) {
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG,
- "PKCS #12: Expected SEQUENCE (ContentInfo) - found class %d tag 0x%x; assume PKCS #12 not used",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "PKCS #12: Expected SEQUENCE (ContentInfo); assume PKCS #12 not used");
return -1;
}
if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
@@ -1141,24 +1085,17 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
*/
/* DHParamer ::= SEQUENCE */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
- "valid SEQUENCE - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "DH: DH parameters did not start with a valid SEQUENCE");
return -1;
}
pos = hdr.payload;
/* prime INTEGER */
- if (asn1_get_next(pos, end - pos, &hdr) < 0)
- return -1;
-
- if (hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
- "class=%d tag=0x%x", hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "DH: No INTEGER tag found for p");
return -1;
}
@@ -1173,13 +1110,9 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
pos = hdr.payload + hdr.length;
/* base INTEGER */
- if (asn1_get_next(pos, end - pos, &hdr) < 0)
- return -1;
-
- if (hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
- "class=%d tag=0x%x", hdr.class, hdr.tag);
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr, "DH: No INTEGER tag found for g");
return -1;
}
@@ -1225,7 +1158,7 @@ static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
return -1;
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
return -1;
diff --git a/contrib/wpa/src/tls/x509v3.c b/contrib/wpa/src/tls/x509v3.c
index 1bd5aa009fb5..b006e99fd538 100644
--- a/contrib/wpa/src/tls/x509v3.c
+++ b/contrib/wpa/src/tls/x509v3.c
@@ -192,12 +192,9 @@ int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
* }
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(AlgorithmIdentifier) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (AlgorithmIdentifier)");
return -1;
}
if (hdr.length > buf + len - hdr.payload)
@@ -234,11 +231,9 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
end = buf + len;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (SubjectPublicKeyInfo)");
return -1;
}
pos = hdr.payload;
@@ -253,18 +248,17 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
return -1;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_BITSTRING) {
- wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
- "(subjectPublicKey) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_bitstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected BITSTRING (subjectPublicKey)");
return -1;
}
if (hdr.length < 1)
return -1;
pos = hdr.payload;
if (*pos) {
- wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ wpa_printf(MSG_DEBUG,
+ "X509: BITSTRING (subjectPublicKey) - %d unused bits",
*pos);
/*
* TODO: should this be rejected? X.509 certificates are
@@ -308,12 +302,9 @@ int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
* AttributeValue ::= ANY DEFINED BY AttributeType
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(Name / RDNSequencer) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (Name / RDNSequencer)");
return -1;
}
pos = hdr.payload;
@@ -327,11 +318,9 @@ int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
enum x509_name_attr_type type;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SET) {
- wpa_printf(MSG_DEBUG, "X509: Expected SET "
- "(RelativeDistinguishedName) - found class "
- "%d tag 0x%x", hdr.class, hdr.tag);
+ !asn1_is_set(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SET (RelativeDistinguishedName)");
x509_free_name(name);
return -1;
}
@@ -340,11 +329,9 @@ int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
pos = set_end = hdr.payload + hdr.length;
if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(AttributeTypeAndValue) - found class %d "
- "tag 0x%x", hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (AttributeTypeAndValue)");
x509_free_name(name);
return -1;
}
@@ -365,6 +352,13 @@ int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
return -1;
}
+ if (!asn1_is_string_type(&hdr)) {
+ wpa_printf(MSG_DEBUG,
+ "X509: Ignore non-string type attribute (tag 0x%x)",
+ hdr.tag);
+ continue;
+ }
+
/* RFC 3280:
* MUST: country, organization, organizational-unit,
* distinguished name qualifier, state or province name,
@@ -708,12 +702,8 @@ static int x509_parse_validity(const u8 *buf, size_t len,
* validity dates in 2050 or later MUST be encoded as GeneralizedTime.
*/
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(Validity) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "X509: Expected SEQUENCE (Validity)");
return -1;
}
pos = hdr.payload;
@@ -725,7 +715,7 @@ static int x509_parse_validity(const u8 *buf, size_t len,
*next = pos + plen;
if (asn1_get_next(pos, plen, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
+ (!asn1_is_utctime(&hdr) && !asn1_is_generalizedtime(&hdr)) ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&cert->not_before) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
@@ -737,7 +727,7 @@ static int x509_parse_validity(const u8 *buf, size_t len,
plen = *next - pos;
if (asn1_get_next(pos, plen, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
+ (!asn1_is_utctime(&hdr) && !asn1_is_generalizedtime(&hdr)) ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&cert->not_after) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
@@ -790,13 +780,9 @@ static int x509_parse_ext_key_usage(struct x509_certificate *cert,
* decipherOnly (8) }
*/
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_BITSTRING ||
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_bitstring(&hdr) ||
hdr.length < 1) {
- wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
- "KeyUsage; found %d tag 0x%x len %d",
- hdr.class, hdr.tag, hdr.length);
+ asn1_unexpected(&hdr, "X509: Expected BIT STRING in KeyUsage");
return -1;
}
@@ -823,12 +809,9 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
*/
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
- "BasicConstraints; found %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE in BasicConstraints");
return -1;
}
@@ -838,14 +821,13 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
return 0;
end_seq = hdr.payload + hdr.length;
- if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL) {
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
return -1;
}
- if (hdr.tag == ASN1_TAG_BOOLEAN) {
+ if (asn1_is_boolean(&hdr)) {
cert->ca = hdr.payload[0];
pos = hdr.payload + hdr.length;
@@ -855,18 +837,16 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
cert->ca);
return 0;
}
- if (asn1_get_next(pos, end_seq - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL) {
+ if (asn1_get_next(pos, end_seq - pos, &hdr) < 0) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
return -1;
}
}
- if (hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
- "BasicConstraints; found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (!asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected INTEGER in BasicConstraints");
return -1;
}
@@ -1073,12 +1053,9 @@ static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
/* SubjectAltName ::= GeneralNames */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
- "SubjectAltName; found %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE in SubjectAltName");
return -1;
}
@@ -1100,12 +1077,9 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
/* IssuerAltName ::= GeneralNames */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
- "IssuerAltName; found %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE in IssuerAltName");
return -1;
}
@@ -1120,6 +1094,130 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
}
+static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
+{
+ return oid->len == 5 &&
+ oid->oid[0] == 2 /* iso/itu-t */ &&
+ oid->oid[1] == 5 /* X.500 Directory Services */ &&
+ oid->oid[2] == 29 /* id-ce */ &&
+ oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
+ oid->oid[4] == 0 /* anyPolicy */;
+}
+
+
+static int x509_id_wfa_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 6 /* dod */ &&
+ oid->oid[3] == 1 /* internet */ &&
+ oid->oid[4] == 4 /* private */ &&
+ oid->oid[5] == 1 /* enterprise */ &&
+ oid->oid[6] == 40808 /* WFA */;
+}
+
+
+static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 9 &&
+ x509_id_wfa_oid(oid) &&
+ oid->oid[7] == 1 &&
+ oid->oid[8] == 3;
+}
+
+
+static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 1;
+}
+
+
+static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 2;
+}
+
+
+static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *end;
+
+ /*
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (certificatePolicies)");
+ return -1;
+ }
+ if (hdr.length > pos + len - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
+
+ while (pos < end) {
+ const u8 *pol_end;
+ struct asn1_oid oid;
+ char buf[80];
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (PolicyInformation)");
+ return -1;
+ }
+ if (hdr.length > end - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ pol_end = pos + hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
+ pos, pol_end - pos);
+
+ if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
+ return -1;
+ if (x509_id_cert_policy_any_oid(&oid)) {
+ os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_ANY;
+ } else if (x509_id_wfa_tod_strict_oid(&oid)) {
+ os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_STRICT;
+ } else if (x509_id_wfa_tod_tofu_oid(&oid)) {
+ os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_TOFU;
+ } else {
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ }
+ wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
+
+ pos = pol_end;
+ }
+
+ cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
+
+ return 0;
+}
+
+
static int x509_id_pkix_oid(struct asn1_oid *oid)
{
return oid->len >= 7 &&
@@ -1182,12 +1280,9 @@ static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
* KeyPurposeId ::= OBJECT IDENTIFIER
*/
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(ExtKeyUsageSyntax) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (ExtKeyUsageSyntax)");
return -1;
}
if (hdr.length > pos + len - hdr.payload)
@@ -1234,7 +1329,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
return 1;
/* TODO: add other extensions required by RFC 3280, Ch 4.2:
- * certificate policies (section 4.2.1.5)
* name constraints (section 4.2.1.11)
* policy constraints (section 4.2.1.12)
* inhibit any-policy (section 4.2.1.15)
@@ -1248,6 +1342,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
return x509_parse_ext_issuer_alt_name(cert, pos, len);
case 19: /* id-ce-basicConstraints */
return x509_parse_ext_basic_constraints(cert, pos, len);
+ case 32: /* id-ce-certificatePolicies */
+ return x509_parse_ext_certificate_policies(cert, pos, len);
case 37: /* id-ce-extKeyUsage */
return x509_parse_ext_ext_key_usage(cert, pos, len);
default:
@@ -1273,12 +1369,8 @@ static int x509_parse_extension(struct x509_certificate *cert,
* }
*/
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
- "Extensions: class %d tag 0x%x; expected SEQUENCE",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "X509: Expected SEQUENCE in Extensions");
return -1;
}
pos = hdr.payload;
@@ -1291,26 +1383,27 @@ static int x509_parse_extension(struct x509_certificate *cert,
}
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- (hdr.tag != ASN1_TAG_BOOLEAN &&
- hdr.tag != ASN1_TAG_OCTETSTRING)) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
- "Extensions: class %d tag 0x%x; expected BOOLEAN "
- "or OCTET STRING", hdr.class, hdr.tag);
+ (!asn1_is_boolean(&hdr) && !asn1_is_octetstring(&hdr))) {
+ asn1_unexpected(&hdr,
+ "X509: Expected BOOLEAN or OCTETSTRING in Extensions");
return -1;
}
if (hdr.tag == ASN1_TAG_BOOLEAN) {
critical_ext = hdr.payload[0];
pos = hdr.payload;
+ /*
+ * Number of CA certificates seem to be using Private class in
+ * one of the X.509v3 extensions, so let's accept that instead
+ * of rejecting the certificate. asn1_is_octetstring() covers
+ * the more common case.
+ */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- (hdr.class != ASN1_CLASS_UNIVERSAL &&
- hdr.class != ASN1_CLASS_PRIVATE) ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
- "in Extensions: class %d tag 0x%x; "
- "expected OCTET STRING",
- hdr.class, hdr.tag);
+ (!asn1_is_octetstring(&hdr) &&
+ !(hdr.class == ASN1_CLASS_PRIVATE &&
+ hdr.tag == ASN1_TAG_OCTETSTRING))) {
+ asn1_unexpected(&hdr,
+ "X509: Expected OCTETSTRING in Extensions");
return -1;
}
}
@@ -1341,12 +1434,8 @@ static int x509_parse_extensions(struct x509_certificate *cert,
/* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
- "for Extensions: class %d tag 0x%x; "
- "expected SEQUENCE", hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "X509: Expected SEQUENCE for Extensions");
return -1;
}
@@ -1375,12 +1464,9 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
const u8 *subject_dn;
/* tbsCertificate TBSCertificate ::= SEQUENCE */
- if (asn1_get_next(buf, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
- "with a valid SEQUENCE - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: tbsCertificate did not start with a valid SEQUENCE");
return -1;
}
pos = hdr.payload;
@@ -1394,15 +1480,11 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
return -1;
pos = hdr.payload;
- if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
- if (asn1_get_next(pos, end - pos, &hdr) < 0)
- return -1;
-
- if (hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER) {
- wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
- "version field - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_is_cs_tag(&hdr, 0) && hdr.constructed) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ !asn1_is_integer(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: No INTEGER tag found for version field");
return -1;
}
if (hdr.length != 1) {
@@ -1435,12 +1517,10 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
/* serialNumber CertificateSerialNumber ::= INTEGER */
- if (hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER ||
+ if (!asn1_is_integer(&hdr) ||
hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
- wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
- "serialNumber; class=%d tag=0x%x length=%u",
- hdr.class, hdr.tag, hdr.length);
+ asn1_unexpected(&hdr,
+ "X509: No INTEGER tag found for serialNumber");
return -1;
}
@@ -1493,10 +1573,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
- wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
- " tag to parse optional tbsCertificate "
- "field(s); parsed class %d tag 0x%x",
- hdr.class, hdr.tag);
+ asn1_unexpected(&hdr,
+ "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
return -1;
}
@@ -1511,10 +1589,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
- wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
- " tag to parse optional tbsCertificate "
- "field(s); parsed class %d tag 0x%x",
- hdr.class, hdr.tag);
+ asn1_unexpected(&hdr,
+ "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
return -1;
}
}
@@ -1530,18 +1606,16 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
- wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
- " tag to parse optional tbsCertificate "
- "field(s); parsed class %d tag 0x%x",
- hdr.class, hdr.tag);
+ asn1_unexpected(&hdr,
+ "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
return -1;
}
}
if (hdr.tag != 3) {
- wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
- "Context-Specific tag %d in optional "
- "tbsCertificate fields", hdr.tag);
+ wpa_printf(MSG_DEBUG,
+ "X509: Ignored unexpected Context-Specific constructed %d tag %d in optional tbsCertificate fields",
+ hdr.constructed, hdr.tag);
return 0;
}
@@ -1669,12 +1743,9 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
/* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
/* Certificate ::= SEQUENCE */
- if (asn1_get_next(pos, len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
- "a valid SEQUENCE - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Certificate did not start with a valid SEQUENCE");
x509_certificate_free(cert);
return NULL;
}
@@ -1709,11 +1780,9 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
/* signatureValue BIT STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_BITSTRING) {
- wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
- "(signatureValue) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_bitstring(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected BITSTRING (signatureValue)");
x509_certificate_free(cert);
return NULL;
}
@@ -1723,7 +1792,8 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
}
pos = hdr.payload;
if (*pos) {
- wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ wpa_printf(MSG_DEBUG,
+ "X509: BITSTRING (signatureValue) - %d unused bits",
*pos);
/* PKCS #1 v1.5 10.2.1:
* It is an error if the length in bits of the signature S is
@@ -1826,14 +1896,12 @@ int x509_check_signature(struct x509_certificate *issuer,
*
*/
if (asn1_get_next(data, data_len, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(DigestInfo) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr, "X509: Expected SEQUENCE (DigestInfo)");
os_free(data);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "X509: DigestInfo", hdr.payload, hdr.length);
pos = hdr.payload;
end = pos + hdr.length;
@@ -1847,14 +1915,14 @@ int x509_check_signature(struct x509_certificate *issuer,
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_SEQUENCE) {
- wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
- "(AlgorithmIdentifier) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_sequence(&hdr)) {
+ asn1_unexpected(&hdr,
+ "X509: Expected SEQUENCE (AlgorithmIdentifier)");
os_free(data);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "X509: DigestAlgorithmIdentifier",
+ hdr.payload, hdr.length);
da_end = hdr.payload + hdr.length;
if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
@@ -1862,6 +1930,23 @@ int x509_check_signature(struct x509_certificate *issuer,
os_free(data);
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "X509: Digest algorithm parameters",
+ next, da_end - next);
+
+ /*
+ * RFC 5754: The correct encoding for the SHA2 algorithms would be to
+ * omit the parameters, but there are implementation that encode these
+ * as a NULL element. Allow these two cases and reject anything else.
+ */
+ if (da_end > next &&
+ (asn1_get_next(next, da_end - next, &hdr) < 0 ||
+ !asn1_is_null(&hdr) ||
+ hdr.payload + hdr.length != da_end)) {
+ wpa_printf(MSG_DEBUG,
+ "X509: Unexpected digest algorithm parameters");
+ os_free(data);
+ return -1;
+ }
if (x509_sha1_oid(&oid)) {
if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) {
@@ -1940,14 +2025,10 @@ int x509_check_signature(struct x509_certificate *issuer,
skip_digest_oid:
/* Digest ::= OCTET STRING */
pos = da_end;
- end = data + data_len;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
- hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_OCTETSTRING) {
- wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
- "(Digest) - found class %d tag 0x%x",
- hdr.class, hdr.tag);
+ !asn1_is_octetstring(&hdr)) {
+ asn1_unexpected(&hdr, "X509: Expected OCTETSTRING (Digest)");
os_free(data);
return -1;
}
diff --git a/contrib/wpa/src/tls/x509v3.h b/contrib/wpa/src/tls/x509v3.h
index 7df8e2ab0870..e3b108ff4381 100644
--- a/contrib/wpa/src/tls/x509v3.h
+++ b/contrib/wpa/src/tls/x509v3.h
@@ -74,6 +74,7 @@ struct x509_certificate {
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
#define X509_EXT_EXT_KEY_USAGE (1 << 5)
+#define X509_EXT_CERTIFICATE_POLICY (1 << 6)
/* BasicConstraints */
int ca; /* cA */
@@ -98,6 +99,12 @@ struct x509_certificate {
#define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2)
#define X509_EXT_KEY_USAGE_OCSP (1 << 3)
+ /* CertificatePolicy */
+ unsigned long certificate_policy;
+#define X509_EXT_CERT_POLICY_ANY (1 << 0)
+#define X509_EXT_CERT_POLICY_TOD_STRICT (1 << 1)
+#define X509_EXT_CERT_POLICY_TOD_TOFU (1 << 2)
+
/*
* The DER format certificate follows struct x509_certificate. These
* pointers point to that buffer.
diff --git a/contrib/wpa/src/utils/Makefile b/contrib/wpa/src/utils/Makefile
new file mode 100644
index 000000000000..d995b8178a1d
--- /dev/null
+++ b/contrib/wpa/src/utils/Makefile
@@ -0,0 +1,30 @@
+#CFLAGS += -DWPA_TRACE
+CFLAGS += -DCONFIG_IPV6
+CFLAGS += -DCONFIG_DEBUG_FILE
+
+LIB_OBJS= \
+ base64.o \
+ bitfield.o \
+ common.o \
+ config.o \
+ crc32.o \
+ ip_addr.o \
+ json.o \
+ radiotap.o \
+ trace.o \
+ uuid.o \
+ wpa_debug.o \
+ wpabuf.o
+
+# Pick correct OS wrapper implementation
+LIB_OBJS += os_unix.o
+
+# Pick correct event loop implementation
+LIB_OBJS += eloop.o
+
+# Pick correct edit implementation
+LIB_OBJS += edit.o
+
+#LIB_OBJS += pcsc_funcs.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/utils/base64.c b/contrib/wpa/src/utils/base64.c
index 53a92f49ed83..0d121c1989ca 100644
--- a/contrib/wpa/src/utils/base64.c
+++ b/contrib/wpa/src/utils/base64.c
@@ -9,21 +9,24 @@
#include "includes.h"
#include <stdint.h>
+#include "utils/common.h"
#include "os.h"
#include "base64.h"
-static const unsigned char base64_table[65] =
+static const char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const unsigned char base64_url_table[65] =
+static const char base64_url_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
- size_t *out_len,
- const unsigned char *table,
- int add_pad)
+#define BASE64_PAD BIT(0)
+#define BASE64_LF BIT(1)
+
+
+static char * base64_gen_encode(const unsigned char *src, size_t len,
+ size_t *out_len, const char *table, int add_pad)
{
- unsigned char *out, *pos;
+ char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;
@@ -31,7 +34,7 @@ static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
if (len >= SIZE_MAX / 4)
return NULL;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
- if (add_pad)
+ if (add_pad & BASE64_LF)
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
@@ -51,7 +54,7 @@ static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[in[2] & 0x3f];
in += 3;
line_len += 4;
- if (add_pad && line_len >= 72) {
+ if ((add_pad & BASE64_LF) && line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
@@ -61,19 +64,19 @@ static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
} else {
*pos++ = table[(((in[0] & 0x03) << 4) |
(in[1] >> 4)) & 0x3f];
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
}
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
line_len += 4;
}
- if (add_pad && line_len)
+ if ((add_pad & BASE64_LF) && line_len)
*pos++ = '\n';
*pos = '\0';
@@ -83,9 +86,8 @@ static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
}
-static unsigned char * base64_gen_decode(const unsigned char *src, size_t len,
- size_t *out_len,
- const unsigned char *table)
+static unsigned char * base64_gen_decode(const char *src, size_t len,
+ size_t *out_len, const char *table)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
@@ -94,12 +96,12 @@ static unsigned char * base64_gen_decode(const unsigned char *src, size_t len,
os_memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
- dtable[table[i]] = (unsigned char) i;
+ dtable[(unsigned char) table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
- if (dtable[src[i]] != 0x80)
+ if (dtable[(unsigned char) src[i]] != 0x80)
count++;
}
@@ -165,17 +167,22 @@ static unsigned char * base64_gen_decode(const unsigned char *src, size_t len,
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
-unsigned char * base64_encode(const unsigned char *src, size_t len,
- size_t *out_len)
+char * base64_encode(const void *src, size_t len, size_t *out_len)
+{
+ return base64_gen_encode(src, len, out_len, base64_table,
+ BASE64_PAD | BASE64_LF);
+}
+
+
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len)
{
- return base64_gen_encode(src, len, out_len, base64_table, 1);
+ return base64_gen_encode(src, len, out_len, base64_table, BASE64_PAD);
}
-unsigned char * base64_url_encode(const unsigned char *src, size_t len,
- size_t *out_len, int add_pad)
+char * base64_url_encode(const void *src, size_t len, size_t *out_len)
{
- return base64_gen_encode(src, len, out_len, base64_url_table, add_pad);
+ return base64_gen_encode(src, len, out_len, base64_url_table, 0);
}
@@ -189,15 +196,13 @@ unsigned char * base64_url_encode(const unsigned char *src, size_t len,
*
* Caller is responsible for freeing the returned buffer.
*/
-unsigned char * base64_decode(const unsigned char *src, size_t len,
- size_t *out_len)
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
{
return base64_gen_decode(src, len, out_len, base64_table);
}
-unsigned char * base64_url_decode(const unsigned char *src, size_t len,
- size_t *out_len)
+unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len)
{
return base64_gen_decode(src, len, out_len, base64_url_table);
}
diff --git a/contrib/wpa/src/utils/base64.h b/contrib/wpa/src/utils/base64.h
index 5a72c3ebf522..d545b2931ca2 100644
--- a/contrib/wpa/src/utils/base64.h
+++ b/contrib/wpa/src/utils/base64.h
@@ -9,13 +9,10 @@
#ifndef BASE64_H
#define BASE64_H
-unsigned char * base64_encode(const unsigned char *src, size_t len,
- size_t *out_len);
-unsigned char * base64_decode(const unsigned char *src, size_t len,
- size_t *out_len);
-unsigned char * base64_url_encode(const unsigned char *src, size_t len,
- size_t *out_len, int add_pad);
-unsigned char * base64_url_decode(const unsigned char *src, size_t len,
- size_t *out_len);
+char * base64_encode(const void *src, size_t len, size_t *out_len);
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len);
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
+char * base64_url_encode(const void *src, size_t len, size_t *out_len);
+unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
#endif /* BASE64_H */
diff --git a/contrib/wpa/src/utils/browser-android.c b/contrib/wpa/src/utils/browser-android.c
index 71a165269cf6..26c83d630a3e 100644
--- a/contrib/wpa/src/utils/browser-android.c
+++ b/contrib/wpa/src/utils/browser-android.c
@@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/contrib/wpa/src/utils/browser-system.c b/contrib/wpa/src/utils/browser-system.c
index aed39706c2e1..d87d97b5ada0 100644
--- a/contrib/wpa/src/utils/browser-system.c
+++ b/contrib/wpa/src/utils/browser-system.c
@@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/contrib/wpa/src/utils/browser-wpadebug.c b/contrib/wpa/src/utils/browser-wpadebug.c
index dfb4b67977f8..d32a85bdf4cd 100644
--- a/contrib/wpa/src/utils/browser-wpadebug.c
+++ b/contrib/wpa/src/utils/browser-wpadebug.c
@@ -63,7 +63,7 @@ static void http_req(void *ctx, struct http_request *req)
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/contrib/wpa/src/utils/browser.c b/contrib/wpa/src/utils/browser.c
index ad0b382fbc11..c0f4380c4e38 100644
--- a/contrib/wpa/src/utils/browser.c
+++ b/contrib/wpa/src/utils/browser.c
@@ -7,7 +7,11 @@
*/
#include "includes.h"
+#ifdef USE_WEBKIT2
+#include <webkit2/webkit2.h>
+#else /* USE_WEBKIT2 */
#include <webkit/webkit.h>
+#endif /* USE_WEBKIT2 */
#include "common.h"
#include "browser.h"
@@ -15,16 +19,20 @@
struct browser_context {
GtkWidget *win;
+ WebKitWebView *view;
int success;
int progress;
char *hover_link;
char *title;
+ int gtk_main_started;
+ int quit_gtk_main;
};
static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
{
wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
- gtk_main_quit();
+ if (ctx->gtk_main_started)
+ gtk_main_quit();
}
@@ -50,6 +58,142 @@ static void browser_update_title(struct browser_context *ctx)
}
+static void process_request_starting_uri(struct browser_context *ctx,
+ const char *uri)
+{
+ int quit = 0;
+
+ if (g_str_has_prefix(uri, "osu://")) {
+ ctx->success = atoi(uri + 6);
+ quit = 1;
+ } else if (g_str_has_prefix(uri, "http://localhost:12345")) {
+ /*
+ * This is used as a special trigger to indicate that the
+ * user exchange has been completed.
+ */
+ ctx->success = 1;
+ quit = 1;
+ }
+
+ if (quit) {
+ if (ctx->gtk_main_started) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ } else {
+ ctx->quit_gtk_main = 1;
+ }
+ }
+}
+
+
+#ifdef USE_WEBKIT2
+
+static void view_cb_notify_estimated_load_progress(WebKitWebView *view,
+ GParamSpec *pspec,
+ struct browser_context *ctx)
+{
+ ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
+ ctx->progress);
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_resource_load_starting(WebKitWebView *view,
+ WebKitWebResource *res,
+ WebKitURIRequest *req,
+ struct browser_context *ctx)
+{
+ const gchar *uri = webkit_uri_request_get_uri(req);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+ process_request_starting_uri(ctx, uri);
+}
+
+
+static gboolean view_cb_decide_policy(WebKitWebView *view,
+ WebKitPolicyDecision *policy,
+ WebKitPolicyDecisionType type,
+ struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
+ switch (type) {
+ case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
+ /* This function makes webkit send a download signal for all
+ * unknown mime types. */
+ WebKitResponsePolicyDecision *response;
+
+ response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
+ if (!webkit_response_policy_decision_is_mime_type_supported(
+ response)) {
+ webkit_policy_decision_download(policy);
+ return TRUE;
+ }
+ break;
+ }
+ case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
+ WebKitNavigationPolicyDecision *d;
+ WebKitNavigationAction *a;
+ WebKitURIRequest *req;
+ const gchar *uri;
+
+ d = WEBKIT_NAVIGATION_POLICY_DECISION(policy);
+ a = webkit_navigation_policy_decision_get_navigation_action(d);
+ req = webkit_navigation_action_get_request(a);
+ uri = webkit_uri_request_get_uri(req);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s navigation action: uri=%s",
+ __func__, uri);
+ process_request_starting_uri(ctx, uri);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void view_cb_mouse_target_changed(WebKitWebView *view,
+ WebKitHitTestResult *h,
+ guint modifiers,
+ struct browser_context *ctx)
+{
+ WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h);
+ const char *uri = NULL;
+
+ if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+ uri = webkit_hit_test_result_get_link_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
+ uri = webkit_hit_test_result_get_image_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
+ uri = webkit_hit_test_result_get_media_uri(h);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A");
+ os_free(ctx->hover_link);
+ if (uri)
+ ctx->hover_link = os_strdup(uri);
+ else
+ ctx->hover_link = NULL;
+
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps,
+ struct browser_context *ctx)
+{
+ const char *title;
+
+ title = webkit_web_view_get_title(ctx->view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
+ os_free(ctx->title);
+ ctx->title = os_strdup(title);
+ browser_update_title(ctx);
+}
+
+#else /* USE_WEBKIT2 */
+
static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
struct browser_context *ctx)
{
@@ -66,6 +210,10 @@ static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
int status = webkit_web_view_get_load_status(view);
wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
__func__, status, webkit_web_view_get_uri(view));
+ if (ctx->quit_gtk_main) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ }
}
@@ -77,21 +225,12 @@ static void view_cb_resource_request_starting(WebKitWebView *view,
struct browser_context *ctx)
{
const gchar *uri = webkit_network_request_get_uri(req);
+
wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
if (g_str_has_suffix(uri, "/favicon.ico"))
webkit_network_request_set_uri(req, "about:blank");
- if (g_str_has_prefix(uri, "osu://")) {
- ctx->success = atoi(uri + 6);
- gtk_main_quit();
- }
- if (g_str_has_prefix(uri, "http://localhost:12345")) {
- /*
- * This is used as a special trigger to indicate that the
- * user exchange has been completed.
- */
- ctx->success = 1;
- gtk_main_quit();
- }
+
+ process_request_starting_uri(ctx, uri);
}
@@ -147,23 +286,32 @@ static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
browser_update_title(ctx);
}
+#endif /* USE_WEBKIT2 */
+
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
GtkWidget *scroll;
- SoupSession *s;
WebKitWebView *view;
+#ifdef USE_WEBKIT2
+ WebKitSettings *settings;
+#else /* USE_WEBKIT2 */
WebKitWebSettings *settings;
+ SoupSession *s;
+#endif /* USE_WEBKIT2 */
struct browser_context ctx;
memset(&ctx, 0, sizeof(ctx));
if (!gtk_init_check(NULL, NULL))
return -1;
+#ifndef USE_WEBKIT2
s = webkit_get_default_session();
g_object_set(G_OBJECT(s), "ssl-ca-file",
"/etc/ssl/certs/ca-certificates.crt", NULL);
- g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+ if (ignore_tls)
+ g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+#endif /* USE_WEBKIT2 */
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
@@ -177,10 +325,24 @@ int hs20_web_browser(const char *url)
G_CALLBACK(win_cb_destroy), &ctx);
view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_signal_connect(G_OBJECT(view), "notify::progress",
- G_CALLBACK(view_cb_notify_progress), &ctx);
+ ctx.view = view;
+#ifdef USE_WEBKIT2
+ g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress",
+ G_CALLBACK(view_cb_notify_estimated_load_progress),
+ &ctx);
+ g_signal_connect(G_OBJECT(view), "resource-load-started",
+ G_CALLBACK(view_cb_resource_load_starting), &ctx);
+ g_signal_connect(G_OBJECT(view), "decide-policy",
+ G_CALLBACK(view_cb_decide_policy), &ctx);
+ g_signal_connect(G_OBJECT(view), "mouse-target-changed",
+ G_CALLBACK(view_cb_mouse_target_changed), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::title",
+ G_CALLBACK(view_cb_notify_title), &ctx);
+#else /* USE_WEBKIT2 */
g_signal_connect(G_OBJECT(view), "notify::load-status",
G_CALLBACK(view_cb_notify_load_status), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::progress",
+ G_CALLBACK(view_cb_notify_progress), &ctx);
g_signal_connect(G_OBJECT(view), "resource-request-starting",
G_CALLBACK(view_cb_resource_request_starting), &ctx);
g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
@@ -191,6 +353,7 @@ int hs20_web_browser(const char *url)
G_CALLBACK(view_cb_hovering_over_link), &ctx);
g_signal_connect(G_OBJECT(view), "title-changed",
G_CALLBACK(view_cb_title_changed), &ctx);
+#endif /* USE_WEBKIT2 */
gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
@@ -205,8 +368,19 @@ int hs20_web_browser(const char *url)
"hs20-client/1.0", NULL);
g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
+#ifdef USE_WEBKIT2
+ if (ignore_tls) {
+ WebKitWebContext *wkctx;
+
+ wkctx = webkit_web_context_get_default();
+ webkit_web_context_set_tls_errors_policy(
+ wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+ }
+#endif /* USE_WEBKIT2 */
+
webkit_web_view_load_uri(view, url);
+ ctx.gtk_main_started = 1;
gtk_main();
gtk_widget_destroy(ctx.win);
while (gtk_events_pending())
diff --git a/contrib/wpa/src/utils/browser.h b/contrib/wpa/src/utils/browser.h
index aaa0eed269f7..3af13b9a11ed 100644
--- a/contrib/wpa/src/utils/browser.h
+++ b/contrib/wpa/src/utils/browser.h
@@ -10,12 +10,12 @@
#define BROWSER_H
#ifdef CONFIG_NO_BROWSER
-static inline int hs20_web_browser(const char *url)
+static inline int hs20_web_browser(const char *url, int ignore_tls)
{
return -1;
}
#else /* CONFIG_NO_BROWSER */
-int hs20_web_browser(const char *url);
+int hs20_web_browser(const char *url, int ignore_tls);
#endif /* CONFIG_NO_BROWSER */
#endif /* BROWSER_H */
diff --git a/contrib/wpa/src/utils/build_config.h b/contrib/wpa/src/utils/build_config.h
index 7d032373c8d3..c6f4e4379ae6 100644
--- a/contrib/wpa/src/utils/build_config.h
+++ b/contrib/wpa/src/utils/build_config.h
@@ -26,8 +26,8 @@
#define PCSC_FUNCS
#define CONFIG_CTRL_IFACE
#define CONFIG_CTRL_IFACE_NAMED_PIPE
-#undef CONFIG_DRIVER_NDIS
-#undef CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
#define CONFIG_DEBUG_FILE
#define EAP_MD5
#define EAP_TLS
diff --git a/contrib/wpa/src/utils/common.c b/contrib/wpa/src/utils/common.c
index 27bf435d9691..2c12751938e5 100644
--- a/contrib/wpa/src/utils/common.c
+++ b/contrib/wpa/src/utils/common.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <limits.h>
#include "common/ieee802_11_defs.h"
#include "common.h"
@@ -790,6 +791,10 @@ int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
*/
pos = value;
while (pos && pos[0]) {
+ if (count == UINT_MAX) {
+ os_free(freq);
+ return -1;
+ }
n = os_realloc_array(freq, count + 1,
sizeof(struct wpa_freq_range));
if (n == NULL) {
@@ -874,9 +879,10 @@ char * freq_range_list_str(const struct wpa_freq_range_list *list)
}
-int int_array_len(const int *a)
+size_t int_array_len(const int *a)
{
- int i;
+ size_t i;
+
for (i = 0; a && a[i]; i++)
;
return i;
@@ -885,12 +891,21 @@ int int_array_len(const int *a)
void int_array_concat(int **res, const int *a)
{
- int reslen, alen, i;
+ size_t reslen, alen, i, max_size;
int *n;
reslen = int_array_len(*res);
alen = int_array_len(a);
-
+ max_size = (size_t) -1;
+ if (alen >= max_size - reslen) {
+ /* This should not really happen, but if it did, something
+ * would overflow. Do not try to merge the arrays; instead, make
+ * this behave like memory allocation failure to avoid messing
+ * up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
@@ -918,8 +933,7 @@ static int freq_cmp(const void *a, const void *b)
void int_array_sort_unique(int *a)
{
- int alen;
- int i, j;
+ size_t alen, i, j;
if (a == NULL)
return;
@@ -944,7 +958,7 @@ void int_array_sort_unique(int *a)
void int_array_add_unique(int **res, int a)
{
- int reslen;
+ size_t reslen, max_size;
int *n;
for (reslen = 0; *res && (*res)[reslen]; reslen++) {
@@ -952,6 +966,16 @@ void int_array_add_unique(int **res, int a)
return; /* already in the list */
}
+ max_size = (size_t) -1;
+ if (reslen > max_size - 2) {
+ /* This should not really happen in practice, but if it did,
+ * something would overflow. Do not try to add the new value;
+ * instead, make this behave like memory allocation failure to
+ * avoid messing up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + 2, sizeof(int));
if (n == NULL) {
os_free(*res);
diff --git a/contrib/wpa/src/utils/common.h b/contrib/wpa/src/utils/common.h
index 17411451d2ed..45f72bb30984 100644
--- a/contrib/wpa/src/utils/common.h
+++ b/contrib/wpa/src/utils/common.h
@@ -344,6 +344,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
#ifndef ETH_P_OUI
#define ETH_P_OUI 0x88B7
#endif /* ETH_P_OUI */
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif /* ETH_P_8021Q */
#ifdef __GNUC__
@@ -479,7 +482,8 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
void buf_shift_right(u8 *buf, size_t len, size_t bits);
void wpa_get_ntp_timestamp(u8 *buf);
-int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
+ PRINTF_FORMAT(3, 4);
int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
char sep);
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
@@ -544,7 +548,7 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
-int int_array_len(const int *a);
+size_t int_array_len(const int *a);
void int_array_concat(int **res, const int *a);
void int_array_sort_unique(int *a);
void int_array_add_unique(int **res, int a);
diff --git a/contrib/wpa/src/utils/config.c b/contrib/wpa/src/utils/config.c
new file mode 100644
index 000000000000..22aa2216eb3f
--- /dev/null
+++ b/contrib/wpa/src/utils/config.c
@@ -0,0 +1,97 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, 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 "utils/config.h"
+#include "common.h"
+
+
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
+
+
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
+ pos = s;
+
+ /* Skip white space from the beginning of line. */
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+
+ /* Skip comment lines and empty lines */
+ if (*pos == '#' || *pos == '\n' || *pos == '\0')
+ continue;
+
+ /*
+ * Remove # comments unless they are within a double quoted
+ * string.
+ */
+ sstart = os_strchr(pos, '"');
+ if (sstart)
+ sstart = os_strrchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = os_strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + os_strlen(pos) - 1;
+
+ /* Remove trailing white space. */
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r'))
+ *end-- = '\0';
+
+ if (*pos == '\0')
+ continue;
+
+ if (_pos)
+ *_pos = pos;
+ return pos;
+ }
+
+ if (_pos)
+ *_pos = NULL;
+ return NULL;
+}
diff --git a/contrib/wpa/src/utils/config.h b/contrib/wpa/src/utils/config.h
new file mode 100644
index 000000000000..074a88a5da3c
--- /dev/null
+++ b/contrib/wpa/src/utils/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef UTILS_CONFIG_H
+#define UTILS_CONFIG_H
+
+/**
+ * wpa_config_get_line - Read the next configuration file line
+ * @s: Buffer for the line
+ * @size: The buffer length
+ * @stream: File stream to read from
+ * @line: Pointer to a variable storing the file line number
+ * @_pos: Buffer for the pointer to the beginning of data on the text line or
+ * %NULL if not needed (returned value used instead)
+ * Returns: Pointer to the beginning of data on the text line or %NULL if no
+ * more text lines are available.
+ *
+ * This function reads the next non-empty line from the configuration file and
+ * removes comments. The returned string is guaranteed to be null-terminated.
+ */
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos);
+
+#endif /* UTILS_CONFIG_H */
diff --git a/contrib/wpa/src/utils/eloop.c b/contrib/wpa/src/utils/eloop.c
index bb375be1095e..b353ab0e467f 100644
--- a/contrib/wpa/src/utils/eloop.c
+++ b/contrib/wpa/src/utils/eloop.c
@@ -68,7 +68,7 @@ struct eloop_signal {
};
struct eloop_sock_table {
- int count;
+ size_t count;
struct eloop_sock *table;
eloop_event_type type;
int changed;
@@ -77,10 +77,10 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
- int count; /* sum of all table counts */
+ size_t count; /* sum of all table counts */
#ifdef CONFIG_ELOOP_POLL
- int max_pollfd_map; /* number of pollfds_map currently allocated */
- int max_poll_fds; /* number of pollfds currently allocated */
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+ size_t max_poll_fds; /* number of pollfds currently allocated */
struct pollfd *pollfds;
struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
@@ -90,12 +90,12 @@ struct eloop_data {
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef CONFIG_ELOOP_EPOLL
int epollfd;
- int epoll_max_event_num;
+ size_t epoll_max_event_num;
struct epoll_event *epoll_events;
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
int kqueuefd;
- int kqueue_nevents;
+ size_t kqueue_nevents;
struct kevent *kqueue_events;
#endif /* CONFIG_ELOOP_KQUEUE */
struct eloop_sock_table readers;
@@ -104,7 +104,7 @@ struct eloop_data {
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -125,7 +125,8 @@ static void eloop_sigsegv_handler(int sig)
static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -139,7 +140,8 @@ static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -266,7 +268,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
#endif /* CONFIG_ELOOP_EPOLL */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
struct eloop_sock *temp_table;
- int next;
+ size_t next;
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
struct eloop_sock *tmp;
int new_max_sock;
@@ -280,7 +282,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
return -1;
#ifdef CONFIG_ELOOP_POLL
- if (new_max_sock >= eloop.max_pollfd_map) {
+ if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
struct pollfd **nmap;
nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
sizeof(struct pollfd *));
@@ -293,7 +295,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
if (eloop.count + 1 > eloop.max_poll_fds) {
struct pollfd *n;
- int nmax = eloop.count + 1 + 50;
+ size_t nmax = eloop.count + 1 + 50;
+
n = os_realloc_array(eloop.pollfds, nmax,
sizeof(struct pollfd));
if (n == NULL)
@@ -385,7 +388,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
#ifdef CONFIG_ELOOP_KQUEUE
struct kevent ke;
#endif /* CONFIG_ELOOP_KQUEUE */
- int i;
+ size_t i;
if (table == NULL || table->table == NULL || table->count == 0)
return;
@@ -444,7 +447,7 @@ static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
struct pollfd **pollfds_map,
int max_pollfd_map)
{
- int i;
+ size_t i;
int nxt = 0;
int fd;
struct pollfd *pfd;
@@ -519,7 +522,7 @@ static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
int max_pollfd_map,
short int revents)
{
- int i;
+ size_t i;
struct pollfd *pfd;
if (!table || !table->table)
@@ -572,7 +575,7 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
FD_ZERO(fds);
@@ -589,7 +592,7 @@ static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
if (table == NULL || table->table == NULL)
return;
@@ -653,7 +656,8 @@ static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
static int eloop_sock_table_requeue(struct eloop_sock_table *table)
{
- int i, r;
+ size_t i;
+ int r;
r = 0;
for (i = 0; i < table->count && table->table; i++) {
@@ -694,7 +698,8 @@ int eloop_sock_requeue(void)
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
{
if (table) {
- int i;
+ size_t i;
+
for (i = 0; i < table->count && table->table; i++) {
wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
"sock=%d eloop_data=%p user_data=%p "
@@ -968,7 +973,7 @@ static void eloop_handle_alarm(int sig)
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
#ifndef CONFIG_NATIVE_WINDOWS
if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
@@ -992,7 +997,7 @@ static void eloop_handle_signal(int sig)
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
diff --git a/contrib/wpa/src/utils/eloop_win.c b/contrib/wpa/src/utils/eloop_win.c
index 9c8b12be8ad8..74eaa33ece9a 100644
--- a/contrib/wpa/src/utils/eloop_win.c
+++ b/contrib/wpa/src/utils/eloop_win.c
@@ -54,7 +54,7 @@ struct eloop_data {
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -422,7 +422,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
#if 0
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
eloop.signaled++;
for (i = 0; i < eloop.signal_count; i++) {
@@ -437,7 +437,7 @@ static void eloop_handle_signal(int sig)
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
@@ -517,7 +517,7 @@ int eloop_register_signal_terminate(eloop_signal_handler handler,
eloop.term_signal.handler = handler;
eloop.term_signal.user_data = user_data;
-
+
return 0;
}
diff --git a/contrib/wpa/src/utils/ext_password.c b/contrib/wpa/src/utils/ext_password.c
index 5615bd72a714..cbf92de8c26d 100644
--- a/contrib/wpa/src/utils/ext_password.c
+++ b/contrib/wpa/src/utils/ext_password.c
@@ -20,6 +20,9 @@ static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+ &ext_password_file,
+#endif /* CONFIG_EXT_PASSWORD_FILE */
NULL
};
diff --git a/contrib/wpa/src/utils/ext_password_file.c b/contrib/wpa/src/utils/ext_password_file.c
new file mode 100644
index 000000000000..4bb0095f3f28
--- /dev/null
+++ b/contrib/wpa/src/utils/ext_password_file.c
@@ -0,0 +1,136 @@
+/*
+ * External backend for file-backed passwords
+ * Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/config.h"
+#include "ext_password_i.h"
+
+
+/**
+ * Data structure for the file-backed password backend.
+ */
+struct ext_password_file_data {
+ char *path; /* path of the password file */
+};
+
+
+/**
+ * ext_password_file_init - Initialize file-backed password backend
+ * @params: Parameters passed by the user.
+ * Returns: Pointer to the initialized backend.
+ *
+ * This function initializes a new file-backed password backend. The user is
+ * expected to initialize this backend with the parameters being the path of
+ * the file that contains the passwords.
+ */
+static void * ext_password_file_init(const char *params)
+{
+ struct ext_password_file_data *data;
+
+ if (!params) {
+ wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+
+ data->path = os_strdup(params);
+ if (!data->path) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+/**
+ * ext_password_file_deinit - Deinitialize file-backed password backend
+ * @ctx: The file-backed password backend
+ *
+ * This function frees all data associated with the file-backed password
+ * backend.
+ */
+static void ext_password_file_deinit(void *ctx)
+{
+ struct ext_password_file_data *data = ctx;
+
+ str_clear_free(data->path);
+ os_free(data);
+}
+
+/**
+ * ext_password_file_get - Retrieve password from the file-backed password backend
+ * @ctx: The file-backed password backend
+ * @name: Name of the password to retrieve
+ * Returns: Buffer containing the password if one was found or %NULL.
+ *
+ * This function tries to find a password identified by name in the password
+ * file. The password is expected to be stored in `NAME=PASSWORD` format.
+ * Comments and empty lines in the file are ignored. Invalid lines will cause
+ * an error message, but will not cause the function to fail.
+ */
+static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
+{
+ struct ext_password_file_data *data = ctx;
+ struct wpabuf *password = NULL;
+ char buf[512], *pos;
+ int line = 0;
+ FILE *f;
+
+ f = fopen(data->path, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR,
+ "EXT PW FILE: could not open file '%s': %s",
+ data->path, strerror(errno));
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ char *sep = os_strchr(pos, '=');
+
+ if (!sep) {
+ wpa_printf(MSG_ERROR, "Invalid password line %d.",
+ line);
+ continue;
+ }
+
+ if (!sep[1]) {
+ wpa_printf(MSG_ERROR, "No password for line %d.", line);
+ continue;
+
+ }
+
+ if (os_strncmp(name, pos, sep - pos) != 0)
+ continue;
+
+ password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
+ goto done;
+ }
+
+ wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
+
+done:
+ forced_memzero(buf, sizeof(buf));
+ fclose(f);
+ return password;
+}
+
+
+const struct ext_password_backend ext_password_file = {
+ .name = "file",
+ .init = ext_password_file_init,
+ .deinit = ext_password_file_deinit,
+ .get = ext_password_file_get,
+};
diff --git a/contrib/wpa/src/utils/ext_password_i.h b/contrib/wpa/src/utils/ext_password_i.h
index 948eaf5421b9..872ccd195b5a 100644
--- a/contrib/wpa/src/utils/ext_password_i.h
+++ b/contrib/wpa/src/utils/ext_password_i.h
@@ -26,4 +26,8 @@ struct wpabuf * ext_password_alloc(size_t len);
extern const struct ext_password_backend ext_password_test;
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+extern const struct ext_password_backend ext_password_file;
+#endif /* CONFIG_EXT_PASSWORD_FILE */
+
#endif /* EXT_PASSWORD_I_H */
diff --git a/contrib/wpa/src/utils/http-utils.h b/contrib/wpa/src/utils/http-utils.h
index 8d4399a37240..d9fc925a2bce 100644
--- a/contrib/wpa/src/utils/http-utils.h
+++ b/contrib/wpa/src/utils/http-utils.h
@@ -28,11 +28,11 @@ struct http_logo {
struct http_cert {
char **dnsname;
- unsigned int num_dnsname;
+ size_t num_dnsname;
struct http_othername *othername;
- unsigned int num_othername;
+ size_t num_othername;
struct http_logo *logo;
- unsigned int num_logo;
+ size_t num_logo;
};
int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/contrib/wpa/src/utils/includes.h b/contrib/wpa/src/utils/includes.h
index 75513fc8c1ef..741fc9c143e4 100644
--- a/contrib/wpa/src/utils/includes.h
+++ b/contrib/wpa/src/utils/includes.h
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <stddef.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
diff --git a/contrib/wpa/src/utils/json.c b/contrib/wpa/src/utils/json.c
index b64433959ff7..dd12f1b6ed3e 100644
--- a/contrib/wpa/src/utils/json.c
+++ b/contrib/wpa/src/utils/json.c
@@ -51,7 +51,7 @@ void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\u%04x",
- data[i]);
+ (unsigned char) data[i]);
}
break;
}
@@ -300,8 +300,10 @@ struct json_token * json_parse(const char *data, size_t data_len)
goto fail;
if (!curr_token) {
token = json_alloc_token(&tokens);
- if (!token)
+ if (!token) {
+ os_free(str);
goto fail;
+ }
token->type = JSON_STRING;
token->string = str;
token->state = JSON_COMPLETED;
@@ -514,8 +516,30 @@ struct wpabuf * json_get_member_base64url(struct json_token *json,
token = json_get_member(json, name);
if (!token || token->type != JSON_STRING)
return NULL;
- buf = base64_url_decode((const unsigned char *) token->string,
- os_strlen(token->string), &buflen);
+ buf = base64_url_decode(token->string, os_strlen(token->string),
+ &buflen);
+ if (!buf)
+ return NULL;
+ ret = wpabuf_alloc_ext_data(buf, buflen);
+ if (!ret)
+ os_free(buf);
+
+ return ret;
+}
+
+
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name)
+{
+ struct json_token *token;
+ unsigned char *buf;
+ size_t buflen;
+ struct wpabuf *ret;
+
+ token = json_get_member(json, name);
+ if (!token || token->type != JSON_STRING)
+ return NULL;
+ buf = base64_decode(token->string, os_strlen(token->string), &buflen);
if (!buf)
return NULL;
ret = wpabuf_alloc_ext_data(buf, buflen);
@@ -574,3 +598,93 @@ void json_print_tree(struct json_token *root, char *buf, size_t buflen)
buf[0] = '\0';
json_print_token(root, 1, buf, buflen);
}
+
+
+void json_add_int(struct wpabuf *json, const char *name, int val)
+{
+ wpabuf_printf(json, "\"%s\":%d", name, val);
+}
+
+
+void json_add_string(struct wpabuf *json, const char *name, const char *val)
+{
+ wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
+}
+
+
+int json_add_string_escape(struct wpabuf *json, const char *name,
+ const void *val, size_t len)
+{
+ char *tmp;
+ size_t tmp_len = 6 * len + 1;
+
+ tmp = os_malloc(tmp_len);
+ if (!tmp)
+ return -1;
+ json_escape_string(tmp, tmp_len, val, len);
+ json_add_string(json, name, tmp);
+ bin_clear_free(tmp, tmp_len);
+ return 0;
+}
+
+
+int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
+ size_t len)
+{
+ char *b64;
+
+ b64 = base64_url_encode(val, len, NULL);
+ if (!b64)
+ return -1;
+ json_add_string(json, name, b64);
+ os_free(b64);
+ return 0;
+}
+
+
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len)
+{
+ char *b64;
+
+ b64 = base64_encode_no_lf(val, len, NULL);
+ if (!b64)
+ return -1;
+ json_add_string(json, name, b64);
+ os_free(b64);
+ return 0;
+}
+
+
+void json_start_object(struct wpabuf *json, const char *name)
+{
+ if (name)
+ wpabuf_printf(json, "\"%s\":", name);
+ wpabuf_put_u8(json, '{');
+}
+
+
+void json_end_object(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, '}');
+}
+
+
+void json_start_array(struct wpabuf *json, const char *name)
+{
+ if (name)
+ wpabuf_printf(json, "\"%s\":", name);
+ wpabuf_put_u8(json, '[');
+}
+
+
+void json_end_array(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, ']');
+}
+
+
+void json_value_sep(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, ',');
+}
diff --git a/contrib/wpa/src/utils/json.h b/contrib/wpa/src/utils/json.h
index 8faa95d8bf20..8448bb0c5c76 100644
--- a/contrib/wpa/src/utils/json.h
+++ b/contrib/wpa/src/utils/json.h
@@ -37,6 +37,21 @@ void json_free(struct json_token *json);
struct json_token * json_get_member(struct json_token *json, const char *name);
struct wpabuf * json_get_member_base64url(struct json_token *json,
const char *name);
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name);
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
+void json_add_int(struct wpabuf *json, const char *name, int val);
+void json_add_string(struct wpabuf *json, const char *name, const char *val);
+int json_add_string_escape(struct wpabuf *json, const char *name,
+ const void *val, size_t len);
+int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
+ size_t len);
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len);
+void json_start_object(struct wpabuf *json, const char *name);
+void json_end_object(struct wpabuf *json);
+void json_start_array(struct wpabuf *json, const char *name);
+void json_end_array(struct wpabuf *json);
+void json_value_sep(struct wpabuf *json);
#endif /* JSON_H */
diff --git a/contrib/wpa/src/utils/list.h b/contrib/wpa/src/utils/list.h
index 85aa5e39cfe1..aa62c0881196 100644
--- a/contrib/wpa/src/utils/list.h
+++ b/contrib/wpa/src/utils/list.h
@@ -46,12 +46,12 @@ static inline void dl_list_del(struct dl_list *item)
item->prev = NULL;
}
-static inline int dl_list_empty(struct dl_list *list)
+static inline int dl_list_empty(const struct dl_list *list)
{
return list->next == list;
}
-static inline unsigned int dl_list_len(struct dl_list *list)
+static inline unsigned int dl_list_len(const struct dl_list *list)
{
struct dl_list *item;
int count = 0;
@@ -76,8 +76,8 @@ static inline unsigned int dl_list_len(struct dl_list *list)
dl_list_entry((list)->prev, type, member))
#define dl_list_for_each(item, list, type, member) \
- for (item = dl_list_first((list), type, member); \
- item && item != dl_list_entry((list), type, member); \
+ for (item = dl_list_entry((list)->next, type, member); \
+ &item->member != (list); \
item = dl_list_entry(item->member.next, type, member))
#define dl_list_for_each_safe(item, n, list, type, member) \
diff --git a/contrib/wpa/src/utils/os_internal.c b/contrib/wpa/src/utils/os_internal.c
index 474c8a372205..feade6ee64dd 100644
--- a/contrib/wpa/src/utils/os_internal.c
+++ b/contrib/wpa/src/utils/os_internal.c
@@ -25,10 +25,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/contrib/wpa/src/utils/os_unix.c b/contrib/wpa/src/utils/os_unix.c
index ce1cf12c7dd9..315c973f3228 100644
--- a/contrib/wpa/src/utils/os_unix.c
+++ b/contrib/wpa/src/utils/os_unix.c
@@ -39,7 +39,7 @@ static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
struct os_alloc_trace {
unsigned int magic;
- struct dl_list list;
+ struct dl_list list __attribute__((aligned(16)));
size_t len;
WPA_TRACE_INFO
} __attribute__((aligned(16)));
@@ -49,10 +49,16 @@ struct os_alloc_trace {
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
@@ -218,40 +224,16 @@ static int os_daemon(int nochdir, int noclose)
#endif /* __APPLE__ */
-#ifdef __FreeBSD__
-#include <err.h>
-#include <libutil.h>
-#include <stdint.h>
-#endif /* __FreeBSD__ */
-
int os_daemonize(const char *pid_file)
{
#if defined(__uClinux__) || defined(__sun__)
return -1;
#else /* defined(__uClinux__) || defined(__sun__) */
-#ifdef __FreeBSD__
- pid_t otherpid;
- struct pidfh *pfh;
-
- pfh = pidfile_open(pid_file, 0600, &otherpid);
- if (pfh == NULL) {
- if (errno == EEXIST) {
- errx(1, "Daemon already running, pid: %jd.",
- (intmax_t)otherpid);
- }
- warn("Cannot open or create pidfile.");
- }
-#endif /* __FreeBSD__ */
-
if (os_daemon(0, 0)) {
perror("daemon");
-#ifdef __FreeBSD__
- pidfile_remove(pfh);
-#endif /* __FreeBSD__ */
return -1;
}
-#ifndef __FreeBSD__
if (pid_file) {
FILE *f = fopen(pid_file, "w");
if (f) {
@@ -259,9 +241,6 @@ int os_daemonize(const char *pid_file)
fclose(f);
}
}
-#else /* __FreeBSD__ */
- pidfile_write(pfh);
-#endif /* __FreeBSD__ */
return -0;
#endif /* defined(__uClinux__) || defined(__sun__) */
@@ -358,6 +337,8 @@ char * os_rel2abs_path(const char *rel_path)
int os_program_init(void)
{
+ unsigned int seed;
+
#ifdef ANDROID
/*
* We ignore errors here since errors are normal if we
@@ -386,6 +367,9 @@ int os_program_init(void)
capset(&header, &cap);
#endif /* ANDROID */
+ if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
+ srandom(seed);
+
return 0;
}
@@ -477,12 +461,13 @@ int os_file_exists(const char *fname)
}
+#if !defined __DragonFly__
int os_fdatasync(FILE *stream)
{
if (!fflush(stream)) {
-#ifdef __linux__
+#if defined __FreeBSD__ || defined __linux__
return fdatasync(fileno(stream));
-#else /* !__linux__ */
+#else /* !__linux__ && !__FreeBSD__ */
#ifdef F_FULLFSYNC
/* OS X does not implement fdatasync(). */
return fcntl(fileno(stream), F_FULLFSYNC);
@@ -494,6 +479,7 @@ int os_fdatasync(FILE *stream)
return -1;
}
+#endif
#ifndef WPA_TRACE
diff --git a/contrib/wpa/src/utils/platform.h b/contrib/wpa/src/utils/platform.h
index 813987eb6606..b2ad856b91b1 100644
--- a/contrib/wpa/src/utils/platform.h
+++ b/contrib/wpa/src/utils/platform.h
@@ -1,21 +1,18 @@
+/*
+ * Platform definitions for Radiotap parser
+ * Copyright (c) 2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
#ifndef PLATFORM_H
#define PLATFORM_H
#include "includes.h"
#include "common.h"
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
-#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p)))
-#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p)))
+#define get_unaligned_le16(p) WPA_GET_LE16((void *) (p))
+#define get_unaligned_le32(p) WPA_GET_LE32((void *) (p))
#endif /* PLATFORM_H */
diff --git a/contrib/wpa/src/utils/radiotap.c b/contrib/wpa/src/utils/radiotap.c
index 71996eb7908f..6dfe298189b5 100644
--- a/contrib/wpa/src/utils/radiotap.c
+++ b/contrib/wpa/src/utils/radiotap.c
@@ -8,10 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See COPYING for more details.
+ * Alternatively, this software may be distributed under the terms of ISC
+ * license, see COPYING for more details.
*/
#include "platform.h"
#include "radiotap_iter.h"
@@ -39,6 +37,8 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+ [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
+ [IEEE80211_RADIOTAP_TIMESTAMP] = { .align = 8, .size = 12, },
/*
* add more here as they are defined in radiotap.h
*/
@@ -111,7 +111,7 @@ int ieee80211_radiotap_iterator_init(
iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
iterator->_next_ns_data = NULL;
iterator->_reset_on_ext = 0;
- iterator->_next_bitmap = &radiotap_header->it_present;
+ iterator->_next_bitmap = (le32 *) (((u8 *) radiotap_header) + offsetof(struct ieee80211_radiotap_header, it_present));
iterator->_next_bitmap++;
iterator->_vns = vns;
iterator->current_namespace = &radiotap_ns;
@@ -222,7 +222,7 @@ static int find_override(struct ieee80211_radiotap_iterator *iterator,
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
- * little-endian format whatever the endianess of your CPU.
+ * little-endian format whatever the endianness of your CPU.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
diff --git a/contrib/wpa/src/utils/radiotap.h b/contrib/wpa/src/utils/radiotap.h
index 460af23d8124..488d5a3b42c8 100644
--- a/contrib/wpa/src/utils/radiotap.h
+++ b/contrib/wpa/src/utils/radiotap.h
@@ -1,190 +1,51 @@
-/*-
- * Copyright (c) 2003, 2004 David Young. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
+ * Copyright (c) 2017 Intel Deutschland GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef __RADIOTAP_H
+#define __RADIOTAP_H
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <stdint.h>
-
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION 0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/* The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
+/**
+ * struct ieee82011_radiotap_header - base radiotap header
*/
struct ieee80211_radiotap_header {
- uint8_t it_version; /* Version 0. Only increases
- * for drastic changes,
- * introduction of compatible
- * new fields does not count.
- */
+ /**
+ * @it_version: radiotap version, always 0
+ */
+ uint8_t it_version;
+
+ /**
+ * @it_pad: padding (or alignment)
+ */
uint8_t it_pad;
- le16 it_len; /* length of the whole
- * header in bytes, including
- * it_version, it_pad,
- * it_len, and data fields.
- */
- le32 it_present; /* A bitmap telling which
- * fields are present. Set bit 31
- * (0x80000000) to extend the
- * bitmap by another 32 bits.
- * Additional extensions are made
- * by setting bit 31.
- */
-};
-/* Name Data type Units
- * ---- --------- -----
- *
- * IEEE80211_RADIOTAP_TSFT __le64 microseconds
- *
- * Value in microseconds of the MAC's 64-bit 802.11 Time
- * Synchronization Function timer when the first bit of the
- * MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
- *
- * Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS uint16_t see below
- *
- * For frequency-hopping radios, the hop set (first byte)
- * and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
- *
- * Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
- * one milliwatt (dBm)
- *
- * RF signal power at the antenna, decibel difference from
- * one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
- * one milliwatt (dBm)
- *
- * RF noise power at the antenna, decibel difference from one
- * milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
- *
- * RF signal power at the antenna, decibel difference from an
- * arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
- *
- * RF noise power at the antenna, decibel difference from an
- * arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
- *
- * Quality of Barker code lock. Unitless. Monotonically
- * nondecreasing with "better" lock strength. Called "Signal
- * Quality" in datasheets. (Is there a standard way to measure
- * this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
- *
- * Transmit power expressed as unitless distance from max
- * power set at factory calibration. 0 is max power.
- * Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
- *
- * Transmit power expressed as decibel distance from max power
- * set at factory calibration. 0 is max power. Monotonically
- * nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
- * one milliwatt (dBm)
- *
- * Transmit power expressed as dBm (decibels from a 1 milliwatt
- * reference). This is the absolute power level measured at
- * the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
- *
- * Properties of transmitted and received frames. See flags
- * defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
- *
- * Unitless indication of the Rx/Tx antenna for this packet.
- * The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
- *
- * Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
- *
- * Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
- *
- * Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
- *
- * Number of unicast retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
- *
- * Contains a bitmap of known fields/flags, the flags, and
- * the MCS index.
- *
- * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss
- *
- * Contains the AMPDU information for the subframe.
- */
-enum ieee80211_radiotap_type {
+ /**
+ * @it_len: overall radiotap header length
+ */
+ le16 it_len;
+
+ /**
+ * @it_present: (first) present word
+ */
+ le32 it_present;
+} STRUCT_PACKED;
+
+/* version is always 0 */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* see the radiotap website for the descriptions */
+enum ieee80211_radiotap_presence {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_FLAGS = 1,
IEEE80211_RADIOTAP_RATE = 2,
@@ -203,9 +64,11 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-
+ /* 18 is XChannel, but it's not defined yet */
IEEE80211_RADIOTAP_MCS = 19,
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+ IEEE80211_RADIOTAP_VHT = 21,
+ IEEE80211_RADIOTAP_TIMESTAMP = 22,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
@@ -213,79 +76,125 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_EXT = 31
};
-/* Channel flags. */
-#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
-#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
-#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
-#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
-#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
-#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
-#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
-#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+/* for IEEE80211_RADIOTAP_FLAGS */
+enum ieee80211_radiotap_flags {
+ IEEE80211_RADIOTAP_F_CFP = 0x01,
+ IEEE80211_RADIOTAP_F_SHORTPRE = 0x02,
+ IEEE80211_RADIOTAP_F_WEP = 0x04,
+ IEEE80211_RADIOTAP_F_FRAG = 0x08,
+ IEEE80211_RADIOTAP_F_FCS = 0x10,
+ IEEE80211_RADIOTAP_F_DATAPAD = 0x20,
+ IEEE80211_RADIOTAP_F_BADFCS = 0x40,
+};
+
+/* for IEEE80211_RADIOTAP_CHANNEL */
+enum ieee80211_radiotap_channel_flags {
+ IEEE80211_CHAN_CCK = 0x0020,
+ IEEE80211_CHAN_OFDM = 0x0040,
+ IEEE80211_CHAN_2GHZ = 0x0080,
+ IEEE80211_CHAN_5GHZ = 0x0100,
+ IEEE80211_CHAN_DYN = 0x0400,
+ IEEE80211_CHAN_HALF = 0x4000,
+ IEEE80211_CHAN_QUARTER = 0x8000,
+};
+
+/* for IEEE80211_RADIOTAP_RX_FLAGS */
+enum ieee80211_radiotap_rx_flags {
+ IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002,
+};
+
+/* for IEEE80211_RADIOTAP_TX_FLAGS */
+enum ieee80211_radiotap_tx_flags {
+ IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001,
+ IEEE80211_RADIOTAP_F_TX_CTS = 0x0002,
+ IEEE80211_RADIOTAP_F_TX_RTS = 0x0004,
+ IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008,
+};
+
+/* for IEEE80211_RADIOTAP_MCS "have" flags */
+enum ieee80211_radiotap_mcs_have {
+ IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01,
+ IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02,
+ IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04,
+ IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08,
+ IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10,
+ IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20,
+};
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
- * during CFP
- */
-#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
- * with short
- * preamble
- */
-#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
- * with WEP encryption
- */
-#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
- * with fragmentation
- */
-#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
-#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
- * 802.11 header and payload
- * (to 32-bit boundary)
- */
-#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */
+enum ieee80211_radiotap_mcs_flags {
+ IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03,
+ IEEE80211_RADIOTAP_MCS_BW_20 = 0,
+ IEEE80211_RADIOTAP_MCS_BW_40 = 1,
+ IEEE80211_RADIOTAP_MCS_BW_20L = 2,
+ IEEE80211_RADIOTAP_MCS_BW_20U = 3,
+
+ IEEE80211_RADIOTAP_MCS_SGI = 0x04,
+ IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08,
+ IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10,
+ IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60,
+ IEEE80211_RADIOTAP_MCS_STBC_1 = 1,
+ IEEE80211_RADIOTAP_MCS_STBC_2 = 2,
+ IEEE80211_RADIOTAP_MCS_STBC_3 = 3,
+ IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5,
+};
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */
+/* for IEEE80211_RADIOTAP_AMPDU_STATUS */
+enum ieee80211_radiotap_ampdu_flags {
+ IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001,
+ IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002,
+ IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004,
+ IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+};
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
- * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
-#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
+/* for IEEE80211_RADIOTAP_VHT */
+enum ieee80211_radiotap_vht_known {
+ IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001,
+ IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004,
+ IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008,
+ IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080,
+ IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100,
+};
-/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
-#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
-#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
-#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
-#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
+enum ieee80211_radiotap_vht_flags {
+ IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01,
+ IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08,
+ IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10,
+ IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20,
+};
-/* For IEEE80211_RADIOTAP_MCS */
-#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
-#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
-#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
-#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
-#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
-#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20
-#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80
+enum ieee80211_radiotap_vht_coding {
+ IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
+};
+/* for IEEE80211_RADIOTAP_TIMESTAMP */
+enum ieee80211_radiotap_timestamp_unit_spos {
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0,
+};
-#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
-#define IEEE80211_RADIOTAP_MCS_BW_20 0
-#define IEEE80211_RADIOTAP_MCS_BW_40 1
-#define IEEE80211_RADIOTAP_MCS_BW_20L 2
-#define IEEE80211_RADIOTAP_MCS_BW_20U 3
-#define IEEE80211_RADIOTAP_MCS_SGI 0x04
-#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
-#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
-#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
-#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
-#define IEEE80211_RADIOTAP_MCS_STBC_1 1
-#define IEEE80211_RADIOTAP_MCS_STBC_2 2
-#define IEEE80211_RADIOTAP_MCS_STBC_3 3
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80
+enum ieee80211_radiotap_timestamp_flags {
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
+};
-#endif /* IEEE80211_RADIOTAP_H */
+#endif /* __RADIOTAP_H */
diff --git a/contrib/wpa/src/utils/state_machine.h b/contrib/wpa/src/utils/state_machine.h
index a51431578455..204c8a85ad45 100644
--- a/contrib/wpa/src/utils/state_machine.h
+++ b/contrib/wpa/src/utils/state_machine.h
@@ -9,7 +9,7 @@
* implement a state machine. In addition to including this header file, each
* file implementing a state machine must define STATE_MACHINE_DATA to be the
* data structure including state variables (enum machine_state,
- * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * bool changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
* as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
* a group of state machines with shared data structure, STATE_MACHINE_ADDR
* needs to be defined to point to the MAC address used in debug output.
@@ -45,7 +45,7 @@ static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
*/
#define SM_ENTRY(machine, state) \
if (!global || sm->machine ## _state != machine ## _ ## state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
" entering state " #state); \
} \
@@ -64,7 +64,7 @@ sm->machine ## _state = machine ## _ ## state;
*/
#define SM_ENTRY_M(machine, _state, data) \
if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
#machine " entering state " #_state); \
} \
@@ -82,7 +82,7 @@ sm->data ## _ ## state = machine ## _ ## _state;
*/
#define SM_ENTRY_MA(machine, _state, data) \
if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
#machine " entering state " #_state, \
MAC2STR(STATE_MACHINE_ADDR)); \
diff --git a/contrib/wpa/src/utils/trace.c b/contrib/wpa/src/utils/trace.c
index 40843432050e..8f12da87bb1b 100644
--- a/contrib/wpa/src/utils/trace.c
+++ b/contrib/wpa/src/utils/trace.c
@@ -146,6 +146,17 @@ struct bfd_data {
unsigned int line;
};
+/*
+ * binutils removed the bfd parameter and renamed things but
+ * those were macros so we can detect their absence.
+ * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5
+ */
+#ifndef bfd_get_section_vma
+#define bfd_get_section_vma(bfd, section) bfd_section_vma(section)
+#endif
+#ifndef bfd_get_section_size
+#define bfd_get_section_size bfd_section_size
+#endif
static void find_addr_sect(bfd *abfd, asection *section, void *obj)
{
diff --git a/contrib/wpa/src/utils/utils_module_tests.c b/contrib/wpa/src/utils/utils_module_tests.c
index 3af4fcde1daa..365f21fb11c6 100644
--- a/contrib/wpa/src/utils/utils_module_tests.c
+++ b/contrib/wpa/src/utils/utils_module_tests.c
@@ -226,7 +226,7 @@ static int int_array_tests(void)
int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
int test3_res[] = { -1, 1, 2, 3, 4, 0 };
int errors = 0;
- int len;
+ size_t len;
wpa_printf(MSG_INFO, "int_array tests");
@@ -296,52 +296,53 @@ static int base64_tests(void)
{
int errors = 0;
unsigned char *res;
+ char *res2;
size_t res_len;
wpa_printf(MSG_INFO, "base64 tests");
- res = base64_encode((const unsigned char *) "", ~0, &res_len);
- if (res) {
+ res2 = base64_encode("", ~0, &res_len);
+ if (res2) {
errors++;
- os_free(res);
+ os_free(res2);
}
- res = base64_encode((const unsigned char *) "=", 1, &res_len);
- if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' ||
- res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ res2 = base64_encode("=", 1, &res_len);
+ if (!res2 || res_len != 5 || res2[0] != 'P' || res2[1] != 'Q' ||
+ res2[2] != '=' || res2[3] != '=' || res2[4] != '\n')
errors++;
- os_free(res);
+ os_free(res2);
- res = base64_encode((const unsigned char *) "=", 1, NULL);
- if (!res || res[0] != 'P' || res[1] != 'Q' ||
- res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ res2 = base64_encode("=", 1, NULL);
+ if (!res2 || res2[0] != 'P' || res2[1] != 'Q' ||
+ res2[2] != '=' || res2[3] != '=' || res2[4] != '\n')
errors++;
- os_free(res);
+ os_free(res2);
- res = base64_decode((const unsigned char *) "", 0, &res_len);
+ res = base64_decode("", 0, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_decode((const unsigned char *) "a", 1, &res_len);
+ res = base64_decode("a", 1, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_decode((const unsigned char *) "====", 4, &res_len);
+ res = base64_decode("====", 4, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_decode((const unsigned char *) "PQ==", 4, &res_len);
+ res = base64_decode("PQ==", 4, &res_len);
if (!res || res_len != 1 || res[0] != '=')
errors++;
os_free(res);
- res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len);
+ res = base64_decode("P.Q-=!=*", 8, &res_len);
if (!res || res_len != 1 || res[0] != '=')
errors++;
os_free(res);
@@ -929,7 +930,7 @@ static int const_time_tests(void)
{ 0, 0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), ~0 },
{ ~0 - 1, ~0 },
{ ~0, ~0 }
};
@@ -940,7 +941,7 @@ static int const_time_tests(void)
{ 0, ~0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), 0 },
{ ~0 - 1, 0 },
{ ~0, 0 }
};
diff --git a/contrib/wpa/src/utils/wpa_debug.c b/contrib/wpa/src/utils/wpa_debug.c
index c336e5389d01..a338a2039bb2 100644
--- a/contrib/wpa/src/utils/wpa_debug.c
+++ b/contrib/wpa/src/utils/wpa_debug.c
@@ -12,8 +12,6 @@
#ifdef CONFIG_DEBUG_SYSLOG
#include <syslog.h>
-
-int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
@@ -32,6 +30,10 @@ static FILE *wpa_debug_tracing_file = NULL;
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
int wpa_debug_timestamp = 0;
+int wpa_debug_syslog = 0;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static FILE *out_file = NULL;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef CONFIG_ANDROID_LOG
@@ -61,8 +63,6 @@ static int wpa_to_android_level(int level)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-
-static FILE *out_file = NULL;
#endif /* CONFIG_DEBUG_FILE */
@@ -76,12 +76,12 @@ void wpa_debug_print_timestamp(void)
os_get_time(&tv);
#ifdef CONFIG_DEBUG_FILE
- if (out_file) {
+ if (out_file)
fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
(unsigned int) tv.usec);
- } else
#endif /* CONFIG_DEBUG_FILE */
- printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+ if (!out_file && !wpa_debug_syslog)
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
#endif /* CONFIG_ANDROID_LOG */
}
@@ -210,35 +210,37 @@ void wpa_printf(int level, const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
if (level >= wpa_debug_level) {
#ifdef CONFIG_ANDROID_LOG
+ va_start(ap, fmt);
__android_log_vprint(wpa_to_android_level(level),
ANDROID_LOG_NAME, fmt, ap);
+ va_end(ap);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
+ va_start(ap, fmt);
vsyslog(syslog_priority(level), fmt, ap);
- } else {
+ va_end(ap);
+ }
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
+ va_start(ap, fmt);
vfprintf(out_file, fmt, ap);
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- vprintf(fmt, ap);
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
+ va_end(ap);
}
#endif /* CONFIG_DEBUG_FILE */
-#ifdef CONFIG_DEBUG_SYSLOG
+ if (!wpa_debug_syslog && !out_file) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
}
-#endif /* CONFIG_DEBUG_SYSLOG */
#endif /* CONFIG_ANDROID_LOG */
}
- va_end(ap);
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
@@ -254,7 +256,7 @@ void wpa_printf(int level, const char *fmt, ...)
static void _wpa_hexdump(int level, const char *title, const u8 *buf,
- size_t len, int show)
+ size_t len, int show, int only_syslog)
{
size_t i;
@@ -345,7 +347,8 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
title, (unsigned long) len, display);
bin_clear_free(strbuf, 1 + 3 * len);
- return;
+ if (only_syslog)
+ return;
}
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
@@ -362,33 +365,32 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
fprintf(out_file, " [REMOVED]");
}
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- if (buf == NULL) {
- printf(" [NULL]");
- } else if (show) {
- for (i = 0; i < len; i++)
- printf(" %02x", buf[i]);
- } else {
- printf(" [REMOVED]");
- }
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
+ if (!wpa_debug_syslog && !out_file) {
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ if (buf == NULL) {
+ printf(" [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ } else {
+ printf(" [REMOVED]");
+ }
+ printf("\n");
+ }
#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, 1);
+ _wpa_hexdump(level, title, buf, len, 1, 0);
}
void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+ _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys, 0);
}
@@ -421,13 +423,11 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
if (level < wpa_debug_level)
return;
#ifdef CONFIG_ANDROID_LOG
- _wpa_hexdump(level, title, buf, len, show);
+ _wpa_hexdump(level, title, buf, len, show, 0);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
- if (wpa_debug_syslog) {
- _wpa_hexdump(level, title, buf, len, show);
- return;
- }
+ if (wpa_debug_syslog)
+ _wpa_hexdump(level, title, buf, len, show, 1);
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
@@ -436,13 +436,13 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
if (buf == NULL) {
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [NULL]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
title, (unsigned long) len);
@@ -466,42 +466,43 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
pos += llen;
len -= llen;
}
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- if (!show) {
- printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
- title, (unsigned long) len);
- return;
}
- if (buf == NULL) {
- printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
- title, (unsigned long) len);
- return;
- }
- printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
- while (len) {
- llen = len > line_len ? line_len : len;
- printf(" ");
- for (i = 0; i < llen; i++)
- printf(" %02x", pos[i]);
- for (i = llen; i < line_len; i++)
+file_done:
+#endif /* CONFIG_DEBUG_FILE */
+ if (!wpa_debug_syslog && !out_file) {
+ if (!show) {
+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ if (buf == NULL) {
+ printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ printf("%s - hexdump_ascii(len=%lu):\n", title,
+ (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ printf(" ");
+ for (i = 0; i < llen; i++)
+ printf(" %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ printf(" ");
printf(" ");
- printf(" ");
- for (i = 0; i < llen; i++) {
- if (isprint(pos[i]))
- printf("%c", pos[i]);
- else
- printf("_");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ printf("%c", pos[i]);
+ else
+ printf("_");
+ }
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf("\n");
+ pos += llen;
+ len -= llen;
}
- for (i = llen; i < line_len; i++)
- printf(" ");
- printf("\n");
- pos += llen;
- len -= llen;
- }
-#ifdef CONFIG_DEBUG_FILE
}
-#endif /* CONFIG_DEBUG_FILE */
#endif /* CONFIG_ANDROID_LOG */
}
diff --git a/contrib/wpa/src/utils/wpa_debug.h b/contrib/wpa/src/utils/wpa_debug.h
index 1fe0b7db7482..c6d5cc647f75 100644
--- a/contrib/wpa/src/utils/wpa_debug.h
+++ b/contrib/wpa/src/utils/wpa_debug.h
@@ -14,9 +14,7 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
-#ifdef CONFIG_DEBUG_SYSLOG
extern int wpa_debug_syslog;
-#endif /* CONFIG_DEBUG_SYSLOG */
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
@@ -305,7 +303,6 @@ void hostapd_logger_register_cb(hostapd_logger_cb_func func);
#define HOSTAPD_MODULE_RADIUS 0x00000004
#define HOSTAPD_MODULE_WPA 0x00000008
#define HOSTAPD_MODULE_DRIVER 0x00000010
-#define HOSTAPD_MODULE_IAPP 0x00000020
#define HOSTAPD_MODULE_MLME 0x00000040
enum hostapd_logger_level {
diff --git a/contrib/wpa/src/utils/wpabuf.h b/contrib/wpa/src/utils/wpabuf.h
index 01da41b324d6..eb1db80912a0 100644
--- a/contrib/wpa/src/utils/wpabuf.h
+++ b/contrib/wpa/src/utils/wpabuf.h
@@ -71,6 +71,21 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
}
/**
+ * wpabuf_cmp - Check if two buffers contain the same data
+ * @a: wpabuf buffer
+ * @b: wpabuf buffer
+ * Returns: 0 if the two buffers contain the same data and non-zero otherwise
+ */
+static inline int wpabuf_cmp(const struct wpabuf *a, const struct wpabuf *b)
+{
+ if (!a && !b)
+ return 0;
+ if (a && b && wpabuf_size(a) == wpabuf_size(b))
+ return os_memcmp(a->buf, b->buf, wpabuf_size(a));
+ return -1;
+}
+
+/**
* wpabuf_head - Get pointer to the head of the buffer data
* @buf: wpabuf buffer
* Returns: Pointer to the head of the buffer data
@@ -118,6 +133,12 @@ static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
WPA_PUT_LE32(pos, data);
}
+static inline void wpabuf_put_le64(struct wpabuf *buf, u64 data)
+{
+ u8 *pos = (u8 *) wpabuf_put(buf, 8);
+ WPA_PUT_LE64(pos, data);
+}
+
static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
{
u8 *pos = (u8 *) wpabuf_put(buf, 2);
@@ -136,6 +157,12 @@ static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
WPA_PUT_BE32(pos, data);
}
+static inline void wpabuf_put_be64(struct wpabuf *buf, u64 data)
+{
+ u8 *pos = (u8 *) wpabuf_put(buf, 8);
+ WPA_PUT_BE64(pos, data);
+}
+
static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
size_t len)
{
diff --git a/contrib/wpa/src/utils/xml_libxml2.c b/contrib/wpa/src/utils/xml_libxml2.c
index 7b6d2764b0ed..d73654eb522d 100644
--- a/contrib/wpa/src/utils/xml_libxml2.c
+++ b/contrib/wpa/src/utils/xml_libxml2.c
@@ -409,7 +409,7 @@ char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node,
if (txt == NULL)
return NULL;
- ret = base64_decode((unsigned char *) txt, strlen(txt), &len);
+ ret = base64_decode(txt, strlen(txt), &len);
if (ret_len)
*ret_len = len;
xml_node_get_text_free(ctx, txt);
diff --git a/contrib/wpa/src/wps/Makefile b/contrib/wpa/src/wps/Makefile
new file mode 100644
index 000000000000..cddc6865a559
--- /dev/null
+++ b/contrib/wpa/src/wps/Makefile
@@ -0,0 +1,28 @@
+CFLAGS += -DCONFIG_P2P
+CFLAGS += -DCONFIG_WPS_OOB
+CFLAGS += -DCONFIG_WPS_NFC
+
+LIB_OBJS= \
+ http_client.o \
+ httpread.o \
+ http_server.o \
+ ndef.o \
+ upnp_xml.o \
+ wps_attr_build.o \
+ wps_attr_parse.o \
+ wps_attr_process.o \
+ wps.o \
+ wps_common.o \
+ wps_dev_attr.o \
+ wps_enrollee.o \
+ wps_er.o \
+ wps_er_ssdp.o \
+ wps_module_tests.o \
+ wps_registrar.o \
+ wps_upnp_ap.o \
+ wps_upnp.o \
+ wps_upnp_event.o \
+ wps_upnp_ssdp.o \
+ wps_upnp_web.o
+
+include ../lib.rules
diff --git a/contrib/wpa/src/wps/upnp_xml.c b/contrib/wpa/src/wps/upnp_xml.c
index a9958eeda80d..ca0925cb5833 100644
--- a/contrib/wpa/src/wps/upnp_xml.c
+++ b/contrib/wpa/src/wps/upnp_xml.c
@@ -235,7 +235,7 @@ struct wpabuf * xml_get_base64_item(const char *data, const char *name,
return NULL;
}
- decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
+ decoded = base64_decode(msg, os_strlen(msg), &len);
os_free(msg);
if (decoded == NULL) {
*ret = UPNP_OUT_OF_MEMORY;
diff --git a/contrib/wpa/src/wps/wps.h b/contrib/wpa/src/wps/wps.h
index 9963c4687551..fed3e284895f 100644
--- a/contrib/wpa/src/wps/wps.h
+++ b/contrib/wpa/src/wps/wps.h
@@ -98,6 +98,7 @@ struct wps_device_data {
u16 config_methods;
struct wpabuf *vendor_ext_m1;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *application_ext;
int p2p;
u8 multi_ap_ext;
@@ -344,6 +345,14 @@ struct wps_registrar_config {
const char *dev_name);
/**
+ * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file
+ * @ctx: Higher layer context data (cb_ctx)
+ * @addr: Enrollee's MAC address
+ * @psk: Pointer to found PSK (output arg)
+ */
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
+ /**
* cb_ctx: Higher layer context data for Registrar callbacks
*/
void *cb_ctx;
@@ -386,11 +395,6 @@ struct wps_registrar_config {
int disable_auto_conf;
/**
- * static_wep_only - Whether the BSS supports only static WEP
- */
- int static_wep_only;
-
- /**
* dualband - Whether this is a concurrent dualband AP
*/
int dualband;
@@ -837,6 +841,10 @@ struct wps_context {
struct wpabuf *ap_nfc_dh_pubkey;
struct wpabuf *ap_nfc_dh_privkey;
struct wpabuf *ap_nfc_dev_pw;
+
+ /* Whether to send WPA2-PSK passphrase as a passphrase instead of PSK
+ * for WPA3-Personal transition mode needs. */
+ bool use_passphrase;
};
struct wps_registrar *
@@ -869,6 +877,11 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
const u8 *oob_dev_pw,
size_t oob_dev_pw_len);
void wps_registrar_flush(struct wps_registrar *reg);
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
diff --git a/contrib/wpa/src/wps/wps_attr_build.c b/contrib/wpa/src/wps/wps_attr_build.c
index 4e872f37295c..f3722567611c 100644
--- a/contrib/wpa/src/wps/wps_attr_build.c
+++ b/contrib/wpa/src/wps/wps_attr_build.c
@@ -175,7 +175,9 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg);
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
@@ -308,6 +310,9 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
auth_types &= ~WPS_AUTH_WPA;
auth_types &= ~WPS_AUTH_WPA2;
auth_types &= ~WPS_AUTH_SHARED;
+#ifdef CONFIG_NO_TKIP
+ auth_types &= ~WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
#ifdef CONFIG_WPS_TESTING
if (wps_force_auth_types_in_use) {
wpa_printf(MSG_DEBUG,
@@ -329,6 +334,9 @@ int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
{
u16 encr_types = WPS_ENCR_TYPES;
encr_types &= ~WPS_ENCR_WEP;
+#ifdef CONFIG_NO_TKIP
+ encr_types &= ~WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
#ifdef CONFIG_WPS_TESTING
if (wps_force_encr_types_in_use) {
wpa_printf(MSG_DEBUG,
@@ -371,8 +379,9 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
u8 hash[SHA256_MAC_LEN];
wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
- wpabuf_len(msg), hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+ wpabuf_len(msg), hash) < 0)
+ return -1;
wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
wpabuf_put_be16(msg, WPS_KWA_LEN);
diff --git a/contrib/wpa/src/wps/wps_attr_process.c b/contrib/wpa/src/wps/wps_attr_process.c
index e8c4579309ab..44436a486249 100644
--- a/contrib/wpa/src/wps/wps_attr_process.c
+++ b/contrib/wpa/src/wps/wps_attr_process.c
@@ -39,9 +39,10 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -70,8 +71,8 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
return -1;
}
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 ||
+ os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
diff --git a/contrib/wpa/src/wps/wps_dev_attr.c b/contrib/wpa/src/wps/wps_dev_attr.c
index b209fea8a4f2..c2e949cb6f21 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.c
+++ b/contrib/wpa/src/wps/wps_dev_attr.c
@@ -242,6 +242,21 @@ int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
}
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+ if (!dev->application_ext)
+ return 0;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: * Application Extension",
+ dev->application_ext);
+ wpabuf_put_be16(msg, ATTR_APPLICATION_EXT);
+ wpabuf_put_be16(msg, wpabuf_len(dev->application_ext));
+ wpabuf_put_buf(msg, dev->application_ext);
+
+ return 0;
+}
+
+
static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
size_t str_len)
{
@@ -424,4 +439,6 @@ void wps_device_data_free(struct wps_device_data *dev)
dev->model_number = NULL;
os_free(dev->serial_number);
dev->serial_number = NULL;
+ wpabuf_free(dev->application_ext);
+ dev->application_ext = NULL;
}
diff --git a/contrib/wpa/src/wps/wps_dev_attr.h b/contrib/wpa/src/wps/wps_dev_attr.h
index a4b4173cdbaf..81fdd5f4e958 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.h
+++ b/contrib/wpa/src/wps/wps_dev_attr.h
@@ -33,6 +33,7 @@ void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext);
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
void wps_device_data_free(struct wps_device_data *dev);
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
unsigned int num_req_dev_types,
const u8 *req_dev_types);
diff --git a/contrib/wpa/src/wps/wps_enrollee.c b/contrib/wpa/src/wps/wps_enrollee.c
index 80ed603fc384..819cd43f6afd 100644
--- a/contrib/wpa/src/wps/wps_enrollee.c
+++ b/contrib/wpa/src/wps/wps_enrollee.c
@@ -880,6 +880,17 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
cred.auth_type |= WPS_AUTH_WPA2PSK;
}
+#ifdef CONFIG_NO_TKIP
+ if (cred.encr_type & WPS_ENCR_TKIP) {
+ wpa_printf(MSG_DEBUG, "WPS: Disable encr_type TKIP");
+ cred.encr_type &= ~WPS_ENCR_TKIP;
+ }
+ if (cred.auth_type & WPS_AUTH_WPAPSK) {
+ wpa_printf(MSG_DEBUG, "WPS: Disable auth_type WPAPSK");
+ cred.auth_type &= ~WPS_AUTH_WPAPSK;
+ }
+#endif /* CONFIG_NO_TKIP */
+
if (wps->wps->cred_cb) {
cred.cred_attr = wpabuf_head(attrs);
cred.cred_attr_len = wpabuf_len(attrs);
diff --git a/contrib/wpa/src/wps/wps_er.c b/contrib/wpa/src/wps/wps_er.c
index b71fa718e096..31d2e50e4cff 100644
--- a/contrib/wpa/src/wps/wps_er.c
+++ b/contrib/wpa/src/wps/wps_er.c
@@ -897,7 +897,7 @@ static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
const struct sockaddr_in *dst,
char **len_ptr, char **body_ptr)
{
- unsigned char *encoded;
+ char *encoded;
size_t encoded_len;
struct wpabuf *buf;
@@ -939,7 +939,7 @@ static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
wpabuf_put_str(buf, "\">\n");
if (encoded) {
wpabuf_printf(buf, "<%s>%s</%s>\n",
- arg_name, (char *) encoded, arg_name);
+ arg_name, encoded, arg_name);
os_free(encoded);
}
diff --git a/contrib/wpa/src/wps/wps_registrar.c b/contrib/wpa/src/wps/wps_registrar.c
index 0ac5b2831379..173fbbd68aa0 100644
--- a/contrib/wpa/src/wps/wps_registrar.c
+++ b/contrib/wpa/src/wps/wps_registrar.c
@@ -17,6 +17,7 @@
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
#include "wps_i.h"
#include "wps_dev_attr.h"
#include "wps_upnp.h"
@@ -159,6 +160,7 @@ struct wps_registrar {
const u8 *pri_dev_type, u16 config_methods,
u16 dev_password_id, u8 request_type,
const char *dev_name);
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
void *cb_ctx;
struct dl_list pins;
@@ -171,7 +173,6 @@ struct wps_registrar {
int sel_reg_union;
int sel_reg_dev_password_id_override;
int sel_reg_config_methods_override;
- int static_wep_only;
int dualband;
int force_per_enrollee_psk;
@@ -681,6 +682,7 @@ wps_registrar_init(struct wps_context *wps,
reg->reg_success_cb = cfg->reg_success_cb;
reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+ reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
reg->cb_ctx = cfg->cb_ctx;
reg->skip_cred_build = cfg->skip_cred_build;
if (cfg->extra_cred) {
@@ -694,7 +696,6 @@ wps_registrar_init(struct wps_context *wps,
reg->disable_auto_conf = cfg->disable_auto_conf;
reg->sel_reg_dev_password_id_override = -1;
reg->sel_reg_config_methods_override = -1;
- reg->static_wep_only = cfg->static_wep_only;
reg->dualband = cfg->dualband;
reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
@@ -1290,6 +1291,15 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
}
+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 **psk)
+{
+ if (!reg->lookup_pskfile_cb)
+ return 0;
+ return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}
+
+
static int wps_set_ie(struct wps_registrar *reg)
{
struct wpabuf *beacon;
@@ -1310,13 +1320,9 @@ static int wps_set_ie(struct wps_registrar *reg)
}
beacon = wpabuf_alloc(400 + vendor_len);
- if (beacon == NULL)
- return -1;
probe = wpabuf_alloc(500 + vendor_len);
- if (probe == NULL) {
- wpabuf_free(beacon);
- return -1;
- }
+ if (!beacon || !probe)
+ goto fail;
auth_macs = wps_authorized_macs(reg, &count);
@@ -1331,19 +1337,14 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
- wps_build_vendor_ext(&reg->wps->dev, beacon)) {
- wpabuf_free(beacon);
- wpabuf_free(probe);
- return -1;
- }
+ wps_build_vendor_ext(&reg->wps->dev, beacon) ||
+ wps_build_application_ext(&reg->wps->dev, beacon))
+ goto fail;
#ifdef CONFIG_P2P
if (wps_build_dev_name(&reg->wps->dev, beacon) ||
- wps_build_primary_dev_type(&reg->wps->dev, beacon)) {
- wpabuf_free(beacon);
- wpabuf_free(probe);
- return -1;
- }
+ wps_build_primary_dev_type(&reg->wps->dev, beacon))
+ goto fail;
#endif /* CONFIG_P2P */
wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
@@ -1361,44 +1362,21 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_probe_config_methods(reg, probe) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
- wps_build_vendor_ext(&reg->wps->dev, probe)) {
- wpabuf_free(beacon);
- wpabuf_free(probe);
- return -1;
- }
+ wps_build_vendor_ext(&reg->wps->dev, probe) ||
+ wps_build_application_ext(&reg->wps->dev, probe))
+ goto fail;
beacon = wps_ie_encapsulate(beacon);
probe = wps_ie_encapsulate(probe);
- if (!beacon || !probe) {
- wpabuf_free(beacon);
- wpabuf_free(probe);
- return -1;
- }
-
- if (reg->static_wep_only) {
- /*
- * Windows XP and Vista clients can get confused about
- * EAP-Identity/Request when they probe the network with
- * EAPOL-Start. In such a case, they may assume the network is
- * using IEEE 802.1X and prompt user for a certificate while
- * the correct (non-WPS) behavior would be to ask for the
- * static WEP key. As a workaround, use Microsoft Provisioning
- * IE to advertise that legacy 802.1X is not supported.
- */
- const u8 ms_wps[7] = {
- WLAN_EID_VENDOR_SPECIFIC, 5,
- /* Microsoft Provisioning IE (00:50:f2:5) */
- 0x00, 0x50, 0xf2, 5,
- 0x00 /* no legacy 802.1X or MS WPS */
- };
- wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
- "into Beacon/Probe Response frames");
- wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
- wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
- }
+ if (!beacon || !probe)
+ goto fail;
return wps_cb_set_ie(reg, beacon, probe);
+fail:
+ wpabuf_free(beacon);
+ wpabuf_free(probe);
+ return -1;
}
@@ -1642,6 +1620,8 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
struct wps_registrar *reg = wps->wps->registrar;
+ const u8 *pskfile_psk;
+ char hex[65];
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1685,8 +1665,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->wps->auth_types, wps->auth_type);
if (wps->auth_type & WPS_AUTH_WPA2PSK)
wps->auth_type = WPS_AUTH_WPA2PSK;
+#ifndef CONFIG_NO_TKIP
else if (wps->auth_type & WPS_AUTH_WPAPSK)
wps->auth_type = WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
else if (wps->auth_type & WPS_AUTH_OPEN)
wps->auth_type = WPS_AUTH_OPEN;
else {
@@ -1708,8 +1690,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->auth_type == WPS_AUTH_WPAPSK) {
if (wps->encr_type & WPS_ENCR_AES)
wps->encr_type = WPS_ENCR_AES;
+#ifndef CONFIG_NO_TKIP
else if (wps->encr_type & WPS_ENCR_TKIP)
wps->encr_type = WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
else {
wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
"type for WPA/WPA2");
@@ -1745,7 +1729,8 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
return -1;
}
os_free(wps->new_psk);
- wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
+ wps->new_psk = (u8 *) base64_encode(r, sizeof(r),
+ &wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
wps->new_psk_len--; /* remove newline */
@@ -1756,23 +1741,29 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
wps->cred.key_len = wps->new_psk_len;
+ } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+ pskfile_psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->use_psk_key && wps->wps->psk_set) {
- char hex[65];
wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
- wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
- os_memcpy(wps->cred.key, hex, 32 * 2);
- wps->cred.key_len = 32 * 2;
- } else if (!wps->wps->registrar->force_per_enrollee_psk &&
- wps->wps->network_key) {
+ wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
+ } else if ((!wps->wps->registrar->force_per_enrollee_psk ||
+ wps->wps->use_passphrase) && wps->wps->network_key) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Use passphrase format for Network key");
os_memcpy(wps->cred.key, wps->wps->network_key,
wps->wps->network_key_len);
wps->cred.key_len = wps->wps->network_key_len;
} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
- char hex[65];
/* Generate a random per-device PSK */
os_free(wps->new_psk);
- wps->new_psk_len = 32;
+ wps->new_psk_len = PMK_LEN;
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
@@ -3481,6 +3472,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
"unselect internal Registrar");
reg->selected_registrar = 0;
reg->pbc = 0;
+ wps_registrar_expire_pins(reg);
wps_registrar_selected_registrar_changed(reg, 0);
}
@@ -3667,6 +3659,35 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
}
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len)
+{
+ if (multi_ap_backhaul_ssid) {
+ os_memcpy(reg->multi_ap_backhaul_ssid,
+ multi_ap_backhaul_ssid, multi_ap_backhaul_ssid_len);
+ reg->multi_ap_backhaul_ssid_len = multi_ap_backhaul_ssid_len;
+ }
+
+ os_free(reg->multi_ap_backhaul_network_key);
+ reg->multi_ap_backhaul_network_key = NULL;
+ reg->multi_ap_backhaul_network_key_len = 0;
+ if (multi_ap_backhaul_network_key) {
+ reg->multi_ap_backhaul_network_key =
+ os_memdup(multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ if (!reg->multi_ap_backhaul_network_key)
+ return -1;
+ reg->multi_ap_backhaul_network_key_len =
+ multi_ap_backhaul_network_key_len;
+ }
+
+ return 0;
+}
+
+
#ifdef CONFIG_WPS_NFC
int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
diff --git a/contrib/wpa/src/wps/wps_upnp.c b/contrib/wpa/src/wps/wps_upnp.c
index 642ebfc38ca9..2ae7ea8dcabd 100644
--- a/contrib/wpa/src/wps/wps_upnp.c
+++ b/contrib/wpa/src/wps/wps_upnp.c
@@ -540,8 +540,9 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
list) {
- event_add(s, buf,
- sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
+ wps_upnp_event_add(
+ s, buf,
+ sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
}
wpabuf_free(buf);
@@ -562,7 +563,7 @@ void subscription_destroy(struct subscription *s)
struct upnp_wps_device_interface *iface;
wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
subscr_addr_free_all(s);
- event_delete_all(s);
+ wps_upnp_event_delete_all(s);
dl_list_for_each(iface, &s->sm->interfaces,
struct upnp_wps_device_interface, list)
upnp_er_remove_notification(iface->wps->registrar, s);
@@ -668,7 +669,7 @@ static int subscription_first_event(struct subscription *s)
"initial WLANEvent");
msg = build_fake_wsc_ack();
if (msg) {
- s->sm->wlanevent = (char *)
+ s->sm->wlanevent =
base64_encode(wpabuf_head(msg),
wpabuf_len(msg), NULL);
wpabuf_free(msg);
@@ -693,7 +694,7 @@ static int subscription_first_event(struct subscription *s)
wpabuf_put_property(buf, "WLANEvent", wlan_event);
wpabuf_put_str(buf, tail);
- ret = event_add(s, buf, 0);
+ ret = wps_upnp_event_add(s, buf, 0);
if (ret) {
wpabuf_free(buf);
return ret;
@@ -770,7 +771,7 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
"WPS UPnP: Subscription %p (SID %s) started with %s",
s, str, callback_urls);
/* Schedule sending this */
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
return s;
}
@@ -843,7 +844,7 @@ int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
}
raw_len = pos;
- val = (char *) base64_encode(raw, raw_len, &val_len);
+ val = base64_encode(raw, raw_len, &val_len);
if (val == NULL)
goto fail;
@@ -861,7 +862,7 @@ fail:
}
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
@@ -902,7 +903,7 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
}
return 0;
}
-#endif /* __FreeBSD__ */
+#endif /* __FreeBSD__ || __APPLE__ */
/**
@@ -950,11 +951,7 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
errno, strerror(errno));
goto fail;
}
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
addr = (struct sockaddr_in *) &req.ifr_addr;
-#else
- addr = (struct sockaddr_in *) &req.ifr_netmask;
-#endif
netmask->s_addr = addr->sin_addr.s_addr;
}
@@ -966,7 +963,8 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
goto fail;
}
os_memcpy(mac, req.ifr_addr.sa_data, 6);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) \
+ || defined(__DragonFly__)
if (eth_get(net_if, mac) < 0) {
wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
goto fail;
@@ -1026,7 +1024,7 @@ static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
advertisement_state_machine_stop(sm, 1);
- event_send_stop_all(sm);
+ wps_upnp_event_send_stop_all(sm);
os_free(sm->wlanevent);
sm->wlanevent = NULL;
os_free(sm->ip_addr_text);
diff --git a/contrib/wpa/src/wps/wps_upnp_ap.c b/contrib/wpa/src/wps/wps_upnp_ap.c
index cca390530a16..b6c9478ffe9b 100644
--- a/contrib/wpa/src/wps/wps_upnp_ap.c
+++ b/contrib/wpa/src/wps/wps_upnp_ap.c
@@ -76,8 +76,10 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
void upnp_er_remove_notification(struct wps_registrar *reg,
struct subscription *s)
{
+ bool was_sel_reg = s->selected_registrar;
+
s->selected_registrar = 0;
eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
- if (reg)
+ if (reg && was_sel_reg)
wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/contrib/wpa/src/wps/wps_upnp_event.c b/contrib/wpa/src/wps/wps_upnp_event.c
index a6018fcf98e9..c0d9e41d9a38 100644
--- a/contrib/wpa/src/wps/wps_upnp_event.c
+++ b/contrib/wpa/src/wps/wps_upnp_event.c
@@ -96,8 +96,8 @@ static struct wps_event_ *event_dequeue(struct subscription *s)
}
-/* event_delete_all -- delete entire event queue and current event */
-void event_delete_all(struct subscription *s)
+/* wps_upnp_event_delete_all -- delete entire event queue and current event */
+void wps_upnp_event_delete_all(struct subscription *s)
{
struct wps_event_ *e;
while ((e = event_dequeue(s)) != NULL)
@@ -134,11 +134,11 @@ static void event_retry(struct wps_event_ *e, int do_next_address)
event_delete(e);
s->last_event_failed = 1;
if (!dl_list_empty(&s->event_queue))
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
return;
}
dl_list_add(&s->event_queue, &e->list);
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
}
@@ -229,7 +229,7 @@ static void event_http_cb(void *ctx, struct http_client *c,
/* Schedule sending more if there is more to send */
if (!dl_list_empty(&s->event_queue))
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
break;
case HTTP_CLIENT_FAILED:
wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
@@ -329,19 +329,19 @@ static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
if (nerrors) {
/* Try again later */
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
}
}
-/* event_send_all_later -- schedule sending events to all subscribers
+/* wps_upnp_event_send_all_later -- schedule sending events to all subscribers
* that need it.
* This avoids two problems:
* -- After getting a subscription, we should not send the first event
* until after our reply is fully queued to be sent back,
* -- Possible stack depth or infinite recursion issues.
*/
-void event_send_all_later(struct upnp_wps_device_sm *sm)
+void wps_upnp_event_send_all_later(struct upnp_wps_device_sm *sm)
{
/*
* The exact time in the future isn't too important. Waiting a bit
@@ -355,8 +355,8 @@ void event_send_all_later(struct upnp_wps_device_sm *sm)
}
-/* event_send_stop_all -- cleanup */
-void event_send_stop_all(struct upnp_wps_device_sm *sm)
+/* wps_upnp_event_send_stop_all -- cleanup */
+void wps_upnp_event_send_stop_all(struct upnp_wps_device_sm *sm)
{
if (sm->event_send_all_queued)
eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
@@ -365,13 +365,14 @@ void event_send_stop_all(struct upnp_wps_device_sm *sm)
/**
- * event_add - Add a new event to a queue
+ * wps_upnp_event_add - Add a new event to a queue
* @s: Subscription
* @data: Event data (is copied; caller retains ownership)
* @probereq: Whether this is a Probe Request event
* Returns: 0 on success, -1 on error, 1 on max event queue limit reached
*/
-int event_add(struct subscription *s, const struct wpabuf *data, int probereq)
+int wps_upnp_event_add(struct subscription *s, const struct wpabuf *data,
+ int probereq)
{
struct wps_event_ *e;
unsigned int len;
@@ -417,6 +418,6 @@ int event_add(struct subscription *s, const struct wpabuf *data, int probereq)
wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
"(queue len %u)", e, s, len + 1);
dl_list_add_tail(&s->event_queue, &e->list);
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
return 0;
}
diff --git a/contrib/wpa/src/wps/wps_upnp_i.h b/contrib/wpa/src/wps/wps_upnp_i.h
index 1359416fb239..6ead7b4e9a30 100644
--- a/contrib/wpa/src/wps/wps_upnp_i.h
+++ b/contrib/wpa/src/wps/wps_upnp_i.h
@@ -178,10 +178,11 @@ int web_listener_start(struct upnp_wps_device_sm *sm);
void web_listener_stop(struct upnp_wps_device_sm *sm);
/* wps_upnp_event.c */
-int event_add(struct subscription *s, const struct wpabuf *data, int probereq);
-void event_delete_all(struct subscription *s);
-void event_send_all_later(struct upnp_wps_device_sm *sm);
-void event_send_stop_all(struct upnp_wps_device_sm *sm);
+int wps_upnp_event_add(struct subscription *s, const struct wpabuf *data,
+ int probereq);
+void wps_upnp_event_delete_all(struct subscription *s);
+void wps_upnp_event_send_all_later(struct upnp_wps_device_sm *sm);
+void wps_upnp_event_send_stop_all(struct upnp_wps_device_sm *sm);
/* wps_upnp_ap.c */
int upnp_er_set_selected_registrar(struct wps_registrar *reg,
diff --git a/contrib/wpa/src/wps/wps_upnp_web.c b/contrib/wpa/src/wps/wps_upnp_web.c
index 7548e8432a68..3c5a97c78406 100644
--- a/contrib/wpa/src/wps/wps_upnp_web.c
+++ b/contrib/wpa/src/wps/wps_upnp_web.c
@@ -765,8 +765,8 @@ static void web_connection_send_reply(struct http_request *req,
if (reply) {
size_t len;
- replydata = (char *) base64_encode(wpabuf_head(reply),
- wpabuf_len(reply), &len);
+ replydata = base64_encode(wpabuf_head(reply), wpabuf_len(reply),
+ &len);
} else
replydata = NULL;
diff --git a/contrib/wpa/wpa_supplicant/Android.mk b/contrib/wpa/wpa_supplicant/Android.mk
index b5d982de3679..f539ce1348ec 100644
--- a/contrib/wpa/wpa_supplicant/Android.mk
+++ b/contrib/wpa/wpa_supplicant/Android.mk
@@ -32,6 +32,10 @@ ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
L_CFLAGS += -DANDROID_LIB_STUB
endif
+ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB_EVENT),)
+L_CFLAGS += -DANDROID_LIB_EVENT
+endif
+
# Disable roaming in wpa_supplicant
ifdef CONFIG_NO_ROAMING
L_CFLAGS += -DCONFIG_NO_ROAMING
@@ -90,12 +94,17 @@ OBJS += notify.c
OBJS += bss.c
OBJS += eap_register.c
OBJS += src/utils/common.c
+OBJS += src/utils/config.c
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
+OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
+OBJS += twt.c
+OBJS += robust_av.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
@@ -164,6 +173,10 @@ ifdef CONFIG_VHT_OVERRIDES
L_CFLAGS += -DCONFIG_VHT_OVERRIDES
endif
+ifdef CONFIG_HE_OVERRIDES
+L_CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -198,8 +211,6 @@ endif
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -210,25 +221,15 @@ endif
ifdef CONFIG_OCV
L_CFLAGS += -DCONFIG_OCV
OBJS += src/common/ocv.c
-CONFIG_IEEE80211W=y
-endif
-
-ifdef CONFIG_IEEE80211W
-L_CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -241,25 +242,40 @@ endif
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
endif
ifdef CONFIG_DPP
L_CFLAGS += -DCONFIG_DPP
OBJS += src/common/dpp.c
+OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
+OBJS += src/common/dpp_crypto.c
+OBJS += src/common/dpp_pkex.c
+OBJS += src/common/dpp_reconfig.c
+OBJS += src/common/dpp_tcp.c
OBJS += dpp_supplicant.c
NEED_AES_SIV=y
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
L_CFLAGS += -DCONFIG_DPP2
endif
@@ -271,7 +287,6 @@ NEED_ECC=y
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
@@ -298,8 +313,6 @@ endif
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -360,11 +373,21 @@ L_CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.c
endif
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+OBJS += pasn_supplicant.c
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -388,6 +411,14 @@ OBJS += src/fst/fst_ctrl_iface.c
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+L_CFLAGS += -DCONFIG_NO_TKIP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -431,7 +462,6 @@ endif
ifdef CONFIG_ERP
L_CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -586,7 +616,6 @@ OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -619,7 +648,6 @@ L_CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
else
L_CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -659,6 +687,8 @@ TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
NEED_T_PRF=y
NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
endif
ifdef CONFIG_EAP_PAX
@@ -698,15 +728,12 @@ CONFIG_IEEE8021X_EAPOL=y
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
NEED_DRAGONFLY=y
endif
@@ -723,7 +750,6 @@ endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -743,7 +769,6 @@ OBJS += src/wps/wps_enrollee.c
OBJS += src/wps/wps_registrar.c
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -860,7 +885,6 @@ OBJS += src/ap/wpa_auth_glue.c
OBJS += src/ap/utils.c
OBJS += src/ap/authsrv.c
OBJS += src/ap/ap_config.c
-OBJS += src/utils/ip_addr.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/tkip_countermeasures.c
OBJS += src/ap/ap_mlme.c
@@ -875,7 +899,6 @@ OBJS += src/ap/bss_load.c
OBJS += src/ap/eap_user_db.c
OBJS += src/ap/neighbor_db.c
OBJS += src/ap/rrm.c
-ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
@@ -883,7 +906,6 @@ endif
ifdef CONFIG_IEEE80211AX
OBJS += src/ap/ieee802_11_he.c
endif
-endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
@@ -903,15 +925,12 @@ OBJS += src/eap_server/eap_server.c
OBJS += src/eap_server/eap_server_identity.c
OBJS += src/eap_server/eap_server_methods.c
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
-endif
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
@@ -929,8 +948,12 @@ endif
ifdef CONFIG_DPP
OBJS += src/ap/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += src/ap/gas_serv.c
endif
ifdef CONFIG_HS20
@@ -1033,7 +1056,6 @@ endif
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -1048,7 +1070,6 @@ OBJS_p += src/crypto/crypto_openssl.c
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1105,13 +1126,12 @@ OBJS += src/tls/tlsv1_client.c
OBJS += src/tls/tlsv1_client_write.c
OBJS += src/tls/tlsv1_client_read.c
OBJS += src/tls/tlsv1_client_ocsp.c
-OBJS += src/tls/asn1.c
+NEED_ASN1=y
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1231,12 +1251,10 @@ endif
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -1244,14 +1262,12 @@ endif
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
L_CFLAGS += -DCONFIG_OPENSSL_CMAC
else
AESOBJS += src/crypto/aes-omac1.c
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1344,7 +1360,6 @@ endif
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -1366,6 +1381,9 @@ endif
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
SHA256OBJS += src/crypto/sha256-kdf.c
@@ -1379,7 +1397,6 @@ L_CFLAGS += -DCONFIG_HMAC_SHA512_KDF
SHA256OBJS += src/crypto/sha512-kdf.c
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1399,6 +1416,10 @@ endif
OBJS += src/crypto/sha512-prf.c
endif
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
endif
@@ -1597,6 +1618,12 @@ L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += src/utils/ext_password_file.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
ifdef NEED_EXT_PASSWORD
OBJS += src/utils/ext_password.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD
@@ -1627,13 +1654,10 @@ endif
OBJS += src/drivers/driver_common.c
-OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
+OBJS += wpa_supplicant.c events.c bssid_ignore.c wpas_glue.c scan.c
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
-ifndef CONFIG_AP
-OBJS_t += src/utils/ip_addr.c
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
OBJS += $(CONFIG_MAIN).c
diff --git a/contrib/wpa/wpa_supplicant/ChangeLog b/contrib/wpa/wpa_supplicant/ChangeLog
index f82e5e0ea5df..a06a93b22175 100644
--- a/contrib/wpa/wpa_supplicant/ChangeLog
+++ b/contrib/wpa/wpa_supplicant/ChangeLog
@@ -533,7 +533,7 @@ ChangeLog for wpa_supplicant
* fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding;
this fixes password with include UTF-8 characters that use
three-byte encoding EAP methods that use NtPasswordHash
- * fixed couple of sequencies where radio work items could get stuck,
+ * fixed couple of sequences where radio work items could get stuck,
e.g., when rfkill blocking happens during scanning or when
scan-for-auth workaround is used
* P2P enhancements/fixes
@@ -627,7 +627,7 @@ ChangeLog for wpa_supplicant
* added 'dup_network <id_s> <id_d> <name>' command; this can be used to
clone the psk field without having toextract it from wpa_supplicant
* fixed GSM authentication on USIM
- * added support for usin epoll in eloop (CONFIG_ELOOP_EPOLL=y)
+ * added support for using epoll in eloop (CONFIG_ELOOP_EPOLL=y)
* fixed some concurrent virtual interface cases with dedicated P2P
management interface to not catch events from removed interface (this
could result in the management interface getting disabled)
@@ -1113,7 +1113,7 @@ ChangeLog for wpa_supplicant
workarounds.
- Add support for AuthorizedMACs attribute.
* TDLS:
- - Propogate TDLS related nl80211 capability flags from kernel and
+ - Propagate TDLS related nl80211 capability flags from kernel and
add them as driver capability flags. If the driver doesn't support
capabilities, assume TDLS is supported internally. When TDLS is
explicitly not supported, disable all user facing TDLS operations.
@@ -2221,7 +2221,7 @@ ChangeLog for wpa_supplicant
* added support for EAP-SIM pseudonyms and fast re-authentication
* added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS
session resumption)
- * added support for EAP-SIM with two challanges
+ * added support for EAP-SIM with two challenges
(phase1="sim_min_num_chal=3" can be used to require three challenges)
* added support for configuring DH/DSA parameters for an ephemeral DH
key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters
@@ -2332,7 +2332,7 @@ ChangeLog for wpa_supplicant
ctrl_interface_group can be used to select which group gets access to
the control interface;
wpa_cli: by default, try to connect to the first interface available
- in /var/run/wpa_supplicant; this path can be overriden with -p option
+ in /var/run/wpa_supplicant; this path can be overridden with -p option
and an interface can be selected with -i option (i.e., in most common
cases, wpa_cli does not need to get any arguments)
* added support for LEAP
diff --git a/contrib/wpa/wpa_supplicant/Makefile b/contrib/wpa/wpa_supplicant/Makefile
new file mode 100644
index 000000000000..271f2aab3118
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/Makefile
@@ -0,0 +1,2073 @@
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
+endif
+
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+ALL += libwpa_client.so
+endif
+
+EXTRA_TARGETS=dynamic_eap_methods
+
+CONFIG_FILE=.config
+include ../src/build.rules
+
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_p
+LIBS_p := $(LIBS)
+endif
+endif
+
+export LIBDIR ?= /usr/local/lib/
+export INCDIR ?= /usr/local/include/
+export BINDIR ?= /usr/local/sbin/
+PKG_CONFIG ?= pkg-config
+
+CFLAGS += $(EXTRA_CFLAGS)
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
+
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../.git),../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+CONFIG_TDLS_TESTING=y
+endif
+
+mkconfig:
+ @if [ -f .config ]; then \
+ echo '.config exists - did not replace it'; \
+ exit 1; \
+ fi
+ echo CONFIG_DRIVER_HOSTAP=y >> .config
+ echo CONFIG_DRIVER_WEXT=y >> .config
+
+$(DESTDIR)$(BINDIR)/%: %
+ install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
+ $(MAKE) -C ../src install
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+ install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so
+ install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h
+endif
+ if ls eap_*.so >/dev/null 2>&1; then \
+ install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
+ cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
+ ; fi
+
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
+OBJS = config.o
+OBJS += notify.o
+OBJS += bss.o
+OBJS += eap_register.o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/config.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/bitfield.o
+OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
+OBJS += op_classes.o
+OBJS += rrm.o
+OBJS += twt.o
+OBJS += robust_av.o
+OBJS_p = wpa_passphrase.o
+OBJS_p += ../src/utils/common.o
+OBJS_p += ../src/utils/wpa_debug.o
+OBJS_p += ../src/utils/wpabuf.o
+OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/common.o
+OBJS_c += ../src/common/cli.o
+OBJS += wmm_ac.o
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS_p += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+OBJS_p += ../src/utils/trace.o
+OBJS_c += ../src/utils/trace.o
+OBJS_priv += ../src/utils/trace.o
+LIBCTRL += ../src/utils/trace.o
+LIBCTRLSO += ../src/utils/trace.c
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD
+LIBS += -lbfd -ldl -liberty -lz
+LIBS_p += -lbfd -ldl -liberty -lz
+LIBS_c += -lbfd -ldl -liberty -lz
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifndef CONFIG_OSX
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+# OS X has an alternate implementation
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_p += -lrt
+endif
+endif
+
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+ifdef CONFIG_ELOOP_EPOLL
+CFLAGS += -DCONFIG_ELOOP_EPOLL
+endif
+
+ifdef CONFIG_ELOOP_KQUEUE
+CFLAGS += -DCONFIG_ELOOP_KQUEUE
+endif
+
+ifdef CONFIG_EAPOL_TEST
+CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_p += -lgcov
+endif
+
+ifdef CONFIG_HT_OVERRIDES
+CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifdef CONFIG_VHT_OVERRIDES
+CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
+ifdef CONFIG_HE_OVERRIDES
+CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.o
+ifndef CONFIG_NO_CONFIG_BLOBS
+NEED_BASE64=y
+endif
+CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.o
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.o
+endif
+
+ifdef CONFIG_NO_CONFIG_WRITE
+CFLAGS += -DCONFIG_NO_CONFIG_WRITE
+endif
+
+ifdef CONFIG_NO_CONFIG_BLOBS
+CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
+endif
+
+ifdef CONFIG_NO_SCAN_PROCESSING
+CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
+endif
+
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+endif
+
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/rsn_supp/wpa_ft.o
+endif
+
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_AES_SIV=y
+CONFIG_SAE=y
+CONFIG_AP=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o
+OBJS += mesh_mpm.o
+OBJS += mesh_rsn.o
+endif
+
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
+NEED_ECC=y
+NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
+endif
+
+ifdef CONFIG_DPP
+CFLAGS += -DCONFIG_DPP
+OBJS += ../src/common/dpp.o
+OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
+OBJS += ../src/common/dpp_crypto.o
+OBJS += ../src/common/dpp_pkex.o
+OBJS += ../src/common/dpp_reconfig.o
+OBJS += ../src/common/dpp_tcp.o
+OBJS += dpp_supplicant.o
+NEED_AES_SIV=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+NEED_ECC=y
+NEED_JSON=y
+NEED_GAS_SERVER=y
+NEED_BASE64=y
+NEED_ASN1=y
+ifdef CONFIG_DPP2
+CFLAGS += -DCONFIG_DPP2
+endif
+endif
+
+ifdef CONFIG_OWE
+CFLAGS += -DCONFIG_OWE
+NEED_ECC=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA384=y
+NEED_SHA512=y
+endif
+
+ifdef CONFIG_FILS
+CFLAGS += -DCONFIG_FILS
+NEED_SHA384=y
+NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
+endif
+
+ifdef CONFIG_MBO
+CONFIG_WNM=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.o
+endif
+
+ifdef CONFIG_TDLS
+CFLAGS += -DCONFIG_TDLS
+OBJS += ../src/rsn_supp/tdls.o
+endif
+
+ifdef CONFIG_TDLS_TESTING
+CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += ../src/rsn_supp/wpa.o
+OBJS += ../src/rsn_supp/preauth.o
+OBJS += ../src/rsn_supp/pmksa_cache.o
+OBJS += ../src/rsn_supp/wpa_ie.o
+OBJS += ../src/common/wpa_common.o
+NEED_AES=y
+NEED_SHA1=y
+NEED_MD5=y
+NEED_RC4=y
+else
+CFLAGS += -DCONFIG_NO_WPA
+ifeq ($(CONFIG_TLS), internal)
+NEED_SHA1=y
+NEED_MD5=y
+endif
+endif
+
+ifdef CONFIG_IBSS_RSN
+NEED_RSN_AUTHENTICATOR=y
+CFLAGS += -DCONFIG_IBSS_RSN
+CFLAGS += -DCONFIG_NO_VLAN
+OBJS += ibss_rsn.o
+endif
+
+ifdef CONFIG_MATCH_IFACE
+CFLAGS += -DCONFIG_MATCH_IFACE
+endif
+
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.o
+OBJS += p2p_supplicant_sd.o
+OBJS += ../src/p2p/p2p.o
+OBJS += ../src/p2p/p2p_utils.o
+OBJS += ../src/p2p/p2p_parse.o
+OBJS += ../src/p2p/p2p_build.o
+OBJS += ../src/p2p/p2p_go_neg.o
+OBJS += ../src/p2p/p2p_sd.o
+OBJS += ../src/p2p/p2p_pd.o
+OBJS += ../src/p2p/p2p_invitation.o
+OBJS += ../src/p2p/p2p_dev_disc.o
+OBJS += ../src/p2p/p2p_group.o
+OBJS += ../src/ap/p2p_hostapd.o
+CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+CFLAGS += -DCONFIG_P2P_STRICT
+endif
+endif
+
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+OBJS += pasn_supplicant.o
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.o
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
+ifdef CONFIG_NO_ROAMING
+CFLAGS += -DCONFIG_NO_ROAMING
+endif
+
+include ../src/drivers/drivers.mak
+ifdef CONFIG_AP
+OBJS_d += $(DRV_BOTH_OBJS)
+CFLAGS += $(DRV_BOTH_CFLAGS)
+LDFLAGS += $(DRV_BOTH_LDFLAGS)
+LIBS += $(DRV_BOTH_LIBS)
+else
+NEED_AP_MLME=
+OBJS_d += $(DRV_WPA_OBJS)
+CFLAGS += $(DRV_WPA_CFLAGS)
+LDFLAGS += $(DRV_WPA_LDFLAGS)
+LIBS += $(DRV_WPA_LIBS)
+endif
+
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
+ifdef CONFIG_WINPCAP
+CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
+endif
+
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_HMAC_SHA256_KDF=y
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += eap_tls.so
+else
+CFLAGS += -DEAP_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+SRC_EAP_PEAP = ../src/eap_peer/eap_peap.c ../src/eap_common/eap_peap_common.c
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += eap_peap.so
+else
+CFLAGS += -DEAP_PEAP
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PEAP))
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += eap_ttls.so
+else
+CFLAGS += -DEAP_TTLS
+OBJS += ../src/eap_peer/eap_ttls.o
+endif
+TLS_FUNCS=y
+ifndef CONFIG_FIPS
+MS_FUNCS=y
+CHAP=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += eap_md5.so
+else
+CFLAGS += -DEAP_MD5
+OBJS += ../src/eap_peer/eap_md5.o
+endif
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2
+SRC_EAP_MSCHAPV2 = ../src/eap_peer/eap_mschapv2.c ../src/eap_peer/mschapv2.c
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += eap_mschapv2.so
+else
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_MSCHAPV2))
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += eap_gtc.so
+else
+CFLAGS += -DEAP_GTC
+OBJS += ../src/eap_peer/eap_gtc.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += eap_otp.so
+else
+CFLAGS += -DEAP_OTP
+OBJS += ../src/eap_peer/eap_otp.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += eap_sim.so
+else
+CFLAGS += -DEAP_SIM
+OBJS += ../src/eap_peer/eap_sim.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += eap_leap.so
+else
+CFLAGS += -DEAP_LEAP
+OBJS += ../src/eap_peer/eap_leap.o
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+SRC_EAP_PSK = ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
+ifeq ($(CONFIG_EAP_PSK), dyn)
+CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += eap_psk.so
+else
+CFLAGS += -DEAP_PSK
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PSK))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += eap_aka.so
+else
+CFLAGS += -DEAP_AKA
+OBJS += ../src/eap_peer/eap_aka.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_PROXY
+CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o
+include eap_proxy_$(CONFIG_EAP_PROXY).mak
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+CFLAGS += -DEAP_AKA_PRIME
+endif
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+NEED_AES=y
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+SRC_EAP_FAST = ../src/eap_peer/eap_fast.c ../src/eap_peer/eap_fast_pac.c
+SRC_EAP_FAST += ../src/eap_common/eap_fast_common.c
+ifeq ($(CONFIG_EAP_FAST), dyn)
+CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += eap_fast.so
+else
+CFLAGS += -DEAP_FAST
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_FAST))
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_TEAP
+# EAP-TEAP
+SRC_EAP_TEAP = ../src/eap_peer/eap_teap.c ../src/eap_peer/eap_teap_pac.c
+SRC_EAP_TEAP += ../src/eap_common/eap_teap_common.c
+ifeq ($(CONFIG_EAP_TEAP), dyn)
+CFLAGS += -DEAP_TEAP_DYNAMIC
+EAPDYN += eap_teap.so
+else
+CFLAGS += -DEAP_TEAP
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_TEAP))
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+endif
+
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+SRC_EAP_PAX = ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c
+ifeq ($(CONFIG_EAP_PAX), dyn)
+CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += eap_pax.so
+else
+CFLAGS += -DEAP_PAX
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PAX))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+SRC_EAP_SAKE = ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += eap_sake.so
+else
+CFLAGS += -DEAP_SAKE
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_SAKE))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+SRC_EAP_GPSK = ../src/eap_peer/eap_gpsk.c ../src/eap_common/eap_gpsk_common.c
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += eap_gpsk.so
+else
+CFLAGS += -DEAP_GPSK
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_GPSK))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_PWD
+ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCONFIG_ECC
+endif
+OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_ECC=y
+NEED_DRAGONFLY=y
+endif
+
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+SRC_EAP_EKE = ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c
+ifeq ($(CONFIG_EAP_EKE), dyn)
+CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += eap_eke.so
+else
+CFLAGS += -DEAP_EKE
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_EKE))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_WPS
+# EAP-WSC
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.o
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_ER
+CONFIG_WPS_UPNP=y
+CFLAGS += -DCONFIG_WPS_ER
+OBJS += ../src/wps/wps_er.o
+OBJS += ../src/wps/wps_er_ssdp.o
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+# EAP-IKEv2
+SRC_EAP_IKEV2 = ../src/eap_peer/eap_ikev2.c
+SRC_EAP_IKEV2 += ../src/eap_peer/ikev2.c
+SRC_EAP_IKEV2 += ../src/eap_common/eap_ikev2_common.c
+SRC_EAP_IKEV2 += ../src/eap_common/ikev2_common.c
+ifeq ($(CONFIG_EAP_IKEV2), dyn)
+CFLAGS += -DEAP_IKEV2_DYNAMIC
+EAPDYN += eap_ikev2.so
+else
+CFLAGS += -DEAP_IKEV2
+OBJS += $(patsubst %.c, %.o, $(SRC_EAP_IKEV2))
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += eap_vendor_test.so
+else
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += ../src/eap_peer/eap_vendor_test.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+# EAP-TNC
+CFLAGS += -DEAP_TNC
+OBJS += ../src/eap_peer/eap_tnc.o
+OBJS += ../src/eap_peer/tncc.o
+NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+endif
+
+ifdef CONFIG_MACSEC
+CFLAGS += -DCONFIG_MACSEC
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_UNWRAP=y
+NEED_AES_WRAP=y
+OBJS += wpas_kay.o
+OBJS += ../src/pae/ieee802_1x_cp.o
+OBJS += ../src/pae/ieee802_1x_kay.o
+OBJS += ../src/pae/ieee802_1x_key.o
+OBJS += ../src/pae/ieee802_1x_secy_ops.o
+ifdef CONFIG_AP
+OBJS += ../src/ap/wpa_auth_kay.o
+endif
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+CFLAGS += -DIEEE8021X_EAPOL
+OBJS += ../src/eapol_supp/eapol_supp_sm.o
+OBJS += ../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o
+NEED_EAP_COMMON=y
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
+endif
+
+ifdef CONFIG_AP
+NEED_EAP_COMMON=y
+NEED_RSN_AUTHENTICATOR=y
+CFLAGS += -DCONFIG_AP
+OBJS += ap.o
+CFLAGS += -DCONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_VLAN
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/bss_load.o
+OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
+OBJS += ../src/ap/ieee802_11_ht.o
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+ifdef CONFIG_IEEE80211AX
+OBJS += ../src/ap/ieee802_11_he.o
+endif
+ifdef CONFIG_WNM_AP
+CFLAGS += -DCONFIG_WNM_AP
+OBJS += ../src/ap/wnm_ap.o
+endif
+ifdef CONFIG_MBO
+OBJS += ../src/ap/mbo_ap.o
+endif
+ifdef CONFIG_FILS
+OBJS += ../src/ap/fils_hlp.o
+endif
+ifdef CONFIG_CTRL_IFACE
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_server/eap_server_identity.o
+OBJS += ../src/eap_server/eap_server_methods.o
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+ifdef CONFIG_IEEE80211AX
+CFLAGS += -DCONFIG_IEEE80211AX
+endif
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
+CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_WPS
+CFLAGS += -DEAP_SERVER_WSC
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o
+endif
+ifdef CONFIG_DPP
+OBJS += ../src/ap/dpp_hostapd.o
+OBJS += ../src/ap/gas_query_ap.o
+NEED_AP_GAS_SERV=y
+endif
+ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
+OBJS += ../src/ap/gas_serv.o
+endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
+endif
+
+ifdef CONFIG_MBO
+OBJS += mbo.o
+CFLAGS += -DCONFIG_MBO
+endif
+
+ifdef NEED_RSN_AUTHENTICATOR
+CFLAGS += -DCONFIG_NO_RADIUS
+NEED_AES_WRAP=y
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+endif
+
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += ../src/utils/pcsc_funcs.o
+# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
+ifdef CONFIG_OSX
+LIBS += -framework PCSC
+else
+LIBS += -lpcsclite -lpthread
+endif
+endif
+endif
+
+ifdef CONFIG_SIM_SIMULATOR
+CFLAGS += -DCONFIG_SIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef CONFIG_USIM_SIMULATOR
+CFLAGS += -DCONFIG_USIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef NEED_MILENAGE
+OBJS += ../src/crypto/milenage.o
+NEED_AES_ENCBLOCK=y
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef CONFIG_SMARTCARD
+CFLAGS += -DCONFIG_SMARTCARD
+endif
+
+ifdef NEED_DRAGONFLY
+OBJS += ../src/common/dragonfly.o
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, EAP_FAST, and
+# EAP_TEAP)
+OBJS += ../src/eap_peer/eap_tls_common.o
+ifndef CONFIG_FIPS
+NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
+endif
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+endif
+
+ifeq ($(CONFIG_TLS), wolfssl)
+ifdef TLS_FUNCS
+CFLAGS += -DWOLFSSL_DER_LOAD
+OBJS += ../src/crypto/tls_wolfssl.o
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+OBJS_p += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_p += -lwolfssl -lm
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../src/crypto/tls_openssl.o
+OBJS += ../src/crypto/tls_openssl_ocsp.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+OBJS_p += ../src/crypto/crypto_openssl.o
+OBJS_priv += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
+ifndef CONFIG_TLS_DEFAULT_CIPHERS
+CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
+endif
+CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_internal.o
+SHA1OBJS += ../src/crypto/sha1-internal.o
+endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o
+OBJS += ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/tlsv1_client_ocsp.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+OBJS_p += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+OBJS_p += ../src/crypto/crypto_internal.o
+NEED_AES_ENC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), linux)
+OBJS += ../src/crypto/crypto_linux.o
+OBJS_p += ../src/crypto/crypto_linux.o
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o
+OBJS += ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/tlsv1_client_ocsp.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_ASN1=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DLTM_FAST
+endif
+CONFIG_INTERNAL_DH_GROUP5=y
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_internal.o
+OBJS += ../src/crypto/sha1-internal.o
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifdef TLS_FUNCS
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifneq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -ldl
+endif
+endif
+endif
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far (see below)
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
+NEED_INTERNAL_AES_WRAP=y
+endif
+endif
+ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+# Seems to be needed at least with BoringSSL
+NEED_INTERNAL_AES_WRAP=y
+CFLAGS += -DCONFIG_OPENSSL_INTERNAL_AES_WRAP
+endif
+ifdef CONFIG_FIPS
+# Have to use internal AES key wrap routines to use OpenSSL EVP since the
+# OpenSSL AES_wrap_key()/AES_unwrap_key() API is not available in FIPS mode.
+NEED_INTERNAL_AES_WRAP=y
+endif
+
+ifdef NEED_INTERNAL_AES_WRAP
+ifneq ($(CONFIG_TLS), linux)
+AESOBJS += ../src/crypto/aes-unwrap.o
+endif
+endif
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+endif
+endif
+ifdef NEED_AES_WRAP
+NEED_AES_ENC=y
+ifdef NEED_INTERNAL_AES_WRAP
+AESOBJS += ../src/crypto/aes-wrap.o
+endif
+endif
+ifdef NEED_AES_CBC
+NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+endif
+endif
+endif
+ifdef NEED_AES_ENC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-enc.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+SHA1OBJS += ../src/crypto/sha1.o
+endif
+endif
+endif
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+else
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
+endif
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+MD5OBJS += ../src/crypto/md5.o
+endif
+endif
+endif
+endif
+endif
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+MD5OBJS += ../src/crypto/md5-internal.o
+endif
+OBJS += $(MD5OBJS)
+OBJS_p += $(MD5OBJS)
+OBJS_priv += $(MD5OBJS)
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+DESOBJS = # none needed when not internal
+ifdef NEED_DES
+ifndef CONFIG_FIPS
+CFLAGS += -DCONFIG_DES
+endif
+ifdef CONFIG_INTERNAL_DES
+DESOBJS += ../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
+
+SHA256OBJS = # none by default
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+SHA256OBJS += ../src/crypto/sha256.o
+endif
+endif
+endif
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
+ifdef CONFIG_INTERNAL_SHA256
+SHA256OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef CONFIG_INTERNAL_SHA384
+CFLAGS += -DCONFIG_INTERNAL_SHA384
+SHA256OBJS += ../src/crypto/sha384-internal.o
+endif
+ifdef CONFIG_INTERNAL_SHA512
+CFLAGS += -DCONFIG_INTERNAL_SHA512
+SHA256OBJS += ../src/crypto/sha512-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += ../src/crypto/sha384-tlsprf.o
+endif
+ifdef NEED_HMAC_SHA256_KDF
+CFLAGS += -DCONFIG_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
+ifdef NEED_HMAC_SHA384_KDF
+CFLAGS += -DCONFIG_HMAC_SHA384_KDF
+OBJS += ../src/crypto/sha384-kdf.o
+endif
+ifdef NEED_HMAC_SHA512_KDF
+CFLAGS += -DCONFIG_HMAC_SHA512_KDF
+OBJS += ../src/crypto/sha512-kdf.o
+endif
+OBJS += $(SHA256OBJS)
+ifdef NEED_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/sha384.o
+endif
+endif
+endif
+endif
+CFLAGS += -DCONFIG_SHA384
+OBJS += ../src/crypto/sha384-prf.o
+endif
+ifdef NEED_SHA512
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
+OBJS += ../src/crypto/sha512.o
+endif
+endif
+endif
+endif
+CFLAGS += -DCONFIG_SHA512
+OBJS += ../src/crypto/sha512-prf.o
+endif
+
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
+OBJS += ../src/crypto/random.o
+endif
+
+ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
+CFLAGS += -DCONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += ../src/common/ctrl_iface_common.o
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp6)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+endif
+OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+OBJS += dbus/dbus_dict_helpers.o
+OBJS += dbus/dbus_new_helpers.o
+OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
+OBJS += dbus/dbus_common.o
+ifdef CONFIG_WPS
+OBJS += dbus/dbus_new_handlers_wps.o
+endif
+ifdef CONFIG_P2P
+OBJS += dbus/dbus_new_handlers_p2p.o
+endif
+ifndef DBUS_LIBS
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
+endif
+ifndef DBUS_INCLUDE
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
+endif
+ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+OBJS += dbus/dbus_new_introspect.o
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+endif
+CFLAGS += $(DBUS_INCLUDE)
+LIBS += $(DBUS_LIBS)
+endif
+
+ifdef CONFIG_READLINE
+OBJS_c += ../src/utils/edit_readline.o
+LIBS_c += -lreadline -lncurses
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32 -lgdi32 -lcrypt32
+LIBS_c += -lws2_32
+LIBS_p += -lws2_32 -lgdi32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+CFLAGS += -DCONFIG_NO_LINUX_PACKET_SOCKET_WAR
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef NEED_SME
+OBJS += sme.o
+CFLAGS += -DCONFIG_SME
+endif
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/hw_features_common.o
+
+ifdef NEED_EAP_COMMON
+OBJS += ../src/eap_common/eap_common.o
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
+endif
+
+ifdef CONFIG_FIPS
+CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
+endif
+endif
+
+OBJS += $(SHA1OBJS) $(DESOBJS)
+
+OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
+OBJS_priv += $(SHA1OBJS)
+
+ifdef CONFIG_BGSCAN_SIMPLE
+CFLAGS += -DCONFIG_BGSCAN_SIMPLE
+OBJS += bgscan_simple.o
+NEED_BGSCAN=y
+endif
+
+ifdef CONFIG_BGSCAN_LEARN
+CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.o
+NEED_BGSCAN=y
+endif
+
+ifdef NEED_BGSCAN
+CFLAGS += -DCONFIG_BGSCAN
+OBJS += bgscan.o
+endif
+
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += ../src/utils/ext_password_file.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
+ifdef NEED_GAS_SERVER
+OBJS += ../src/common/gas_server.o
+CFLAGS += -DCONFIG_GAS_SERVER
+NEED_GAS=y
+endif
+
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += gas_query.o
+CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.o
+CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+ifdef NEED_JSON
+OBJS += ../src/utils/json.o
+CFLAGS += -DCONFIG_JSON
+endif
+
+ifdef CONFIG_MODULE_TESTS
+CFLAGS += -DCONFIG_MODULE_TESTS
+OBJS += wpas_module_tests.o
+OBJS += ../src/utils/utils_module_tests.o
+OBJS += ../src/common/common_module_tests.o
+OBJS += ../src/crypto/crypto_module_tests.o
+ifdef CONFIG_WPS
+OBJS += ../src/wps/wps_module_tests.o
+endif
+endif
+
+OBJS += ../src/drivers/driver_common.o
+OBJS_priv += ../src/drivers/driver_common.o
+
+OBJS += wpa_supplicant.o events.o bssid_ignore.o wpas_glue.o scan.o
+OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
+OBJS_t += ../src/radius/radius_client.o
+OBJS_t += ../src/radius/radius.o
+OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+
+OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
+OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o
+
+OBJS += $(CONFIG_MAIN).o
+
+ifdef CONFIG_PRIVSEP
+OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o
+OBJS_priv += $(OBJS_l2)
+OBJS_priv += ../src/utils/os_$(CONFIG_OS).o
+OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_priv += ../src/utils/common.o
+OBJS_priv += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/wpabuf.o
+OBJS_priv += wpa_priv.o
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += ../src/common/ieee802_11_common.o
+endif
+OBJS += ../src/l2_packet/l2_packet_privsep.o
+OBJS += ../src/drivers/driver_privsep.o
+EXTRA_progs += wpa_priv
+else
+OBJS += $(OBJS_d) ../src/drivers/drivers.o
+OBJS += $(OBJS_l2)
+endif
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += ../src/drivers/ndis_events.o
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifdef CONFIG_FST
+CFLAGS += -DCONFIG_FST
+ifdef CONFIG_FST_TEST
+CFLAGS += -DCONFIG_FST_TEST
+endif
+FST_OBJS += ../src/fst/fst.o
+FST_OBJS += ../src/fst/fst_session.o
+FST_OBJS += ../src/fst/fst_iface.o
+FST_OBJS += ../src/fst/fst_group.o
+FST_OBJS += ../src/fst/fst_ctrl_aux.o
+ifdef CONFIG_CTRL_IFACE
+FST_OBJS += ../src/fst/fst_ctrl_iface.o
+endif
+OBJS += $(FST_OBJS)
+OBJS_t += $(FST_OBJS)
+OBJS_t2 += $(FST_OBJS)
+OBJS_nfc += $(FST_OBJS)
+endif
+
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+CFLAGS += -DCONFIG_NO_TKIP
+endif
+
+dynamic_eap_methods: $(EAPDYN)
+
+_OBJS_VAR := OBJS_priv
+include ../src/objs.mk
+wpa_priv: $(BCHECK) $(OBJS_priv)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS
+include ../src/objs.mk
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS_t
+include ../src/objs.mk
+eapol_test: $(OBJS_t)
+ $(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS_t2
+include ../src/objs.mk
+preauth_test: $(OBJS_t2)
+ $(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS_p
+include ../src/objs.mk
+wpa_passphrase: $(OBJS_p)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
+wpa_cli: $(OBJS_c)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+ @$(E) " LD " $@
+
+LIBCTRL += ../src/common/wpa_ctrl.o
+LIBCTRL += ../src/utils/os_$(CONFIG_OS).o
+LIBCTRL += ../src/utils/common.o
+LIBCTRL += ../src/utils/wpa_debug.o
+LIBCTRLSO += ../src/common/wpa_ctrl.c
+LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c
+LIBCTRLSO += ../src/utils/common.c
+LIBCTRLSO += ../src/utils/wpa_debug.c
+
+_OBJS_VAR := LIBCTRL
+include ../src/objs.mk
+libwpa_client.a: $(LIBCTRL)
+ $(Q)rm -f $@
+ $(Q)$(AR) crs $@ $?
+ @$(E) " AR " $@
+
+libwpa_client.so: $(LIBCTRLSO)
+ @$(E) " CC $@ ($^)"
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
+
+OBJS_wpatest := libwpa_test.o
+_OBJS_VAR := OBJS_wpatest
+include ../src/objs.mk
+libwpa_test1: $(OBJS_wpatest) libwpa_client.a
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 $(OBJS_wpatest) libwpa_client.a $(LIBS_c)
+ @$(E) " LD " $@
+
+libwpa_test2: $(OBJS_wpatest) libwpa_client.so
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 $(OBJS_wpatest) -L. -lwpa_client $(LIBS_c)
+ @$(E) " LD " $@
+
+_OBJS_VAR := OBJS_nfc
+include ../src/objs.mk
+nfc_pw_token: $(OBJS_nfc)
+ $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
+ @$(E) " LD " $@
+
+win_if_list: win_if_list.c
+ $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+ @$(E) " LD " $@
+
+eap_psk.so: $(SRC_EAP_PSK)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_psk_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_pax.so: $(SRC_EAP_PAX)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_peap.so: $(SRC_EAP_PEAP)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_sake.so: $(SRC_EAP_SAKE)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_ikev2.so: $(SRC_EAP_IKEV2)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_eke.so: $(SRC_EAP_EKE)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_mschapv2.so: $(SRC_EAP_MSCHAPV2)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_fast.so: $(SRC_EAP_FAST)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_teap.so: $(SRC_EAP_TEAP)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+eap_gpsk.so: $(SRC_EAP_GPSK)
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+%.so: ../src/eap_peer/%.c
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
+ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+ @$(E) " CC/LD " $@
+
+%.service: %.service.in
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ @$(E) " sed" $<
+
+%@.service: %.service.arg.in
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ @$(E) " sed" $<
+
+wpa_supplicant.exe: wpa_supplicant
+ mv -f $< $@
+wpa_cli.exe: wpa_cli
+ mv -f $< $@
+wpa_passphrase.exe: wpa_passphrase
+ mv -f $< $@
+win_if_list.exe: win_if_list
+ mv -f $< $@
+eapol_test.exe: eapol_test
+ mv -f $< $@
+
+WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
+
+windows-bin: $(WINALL)
+ $(STRIP) $(WINALL)
+
+wpa_gui:
+ @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
+
+wpa_gui-qt4/Makefile:
+ qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro
+
+wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts
+ lrelease wpa_gui-qt4/wpa_gui.pro
+
+wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm
+ $(MAKE) -C wpa_gui-qt4
+
+FIPSDIR=/usr/local/ssl/fips-2.0
+FIPSLD=$(FIPSDIR)/bin/fipsld
+fips:
+ $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
+.PHONY: lcov-html
+lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda)
+ lcov -c -d $(BUILDDIR) > lcov.info
+ genhtml lcov.info --output-directory lcov-html
+
+clean: common-clean
+ $(MAKE) -C ../src clean
+ $(MAKE) -C dbus clean
+ rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f eap_*.so $(WINALL) eapol_test preauth_test
+ rm -f wpa_priv
+ rm -f nfc_pw_token
+ rm -f lcov.info
+ rm -rf lcov-html
+ rm -f libwpa_client.a
+ rm -f libwpa_client.so
+ rm -f libwpa_test1 libwpa_test2
diff --git a/contrib/wpa/wpa_supplicant/README b/contrib/wpa/wpa_supplicant/README
index bbc86b137424..391912e9b6c5 100644
--- a/contrib/wpa/wpa_supplicant/README
+++ b/contrib/wpa/wpa_supplicant/README
@@ -383,7 +383,7 @@ cp wpa_cli wpa_supplicant /usr/local/bin
You will need to make a configuration file, e.g.,
/etc/wpa_supplicant.conf, with network configuration for the networks
you are going to use. Configuration file section below includes
-explanation fo the configuration file format and includes various
+explanation of the configuration file format and includes various
examples. Once the configuration is ready, you can test whether the
configuration work by first running wpa_supplicant with following
command to start it on foreground with debugging enabled:
@@ -778,7 +778,7 @@ wpa_cli commands
disconnect = disconnect and wait for reassociate command before connecting
scan = request new BSS scan
scan_results = get latest scan results
- get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
+ get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilities
terminate = terminate wpa_supplicant
quit = exit wpa_cli
diff --git a/contrib/wpa/wpa_supplicant/README-DPP b/contrib/wpa/wpa_supplicant/README-DPP
index dcc15f165c17..d378245cd6de 100644
--- a/contrib/wpa/wpa_supplicant/README-DPP
+++ b/contrib/wpa/wpa_supplicant/README-DPP
@@ -9,42 +9,44 @@ Connector mechanism.
Introduction to DPP
-------------------
-Device provisioning Protocol allows enrolling of interface-less devices
-in a secure Wi-Fi network using many methods like QR code based
-authentication( detailed below ), PKEX based authentication etc. In DPP
-a Configurator is used to provide network credentials to the devices.
-The three phases of DPP connection are authentication, configuration and
+Device Provisioning Protocol (also known as Wi-Fi Easy Connect) allows
+enrolling of interface-less devices in a secure Wi-Fi network using many
+methods like QR code based authentication (detailed below), PKEX based
+authentication (password with in-band provisioning), etc. In DPP a
+Configurator is used to provide network credentials to the devices. The
+three phases of DPP connection are authentication, configuration and
network introduction.
+More information about Wi-Fi Easy Connect is available from this Wi-Fi
+Alliance web page:
+https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect
+
Build config setup
------------------
-The following changes must go in the config file used to compile hostapd
-and wpa_supplicant.
+The following parameters must be included in the config file used to
+compile hostapd and wpa_supplicant.
wpa_supplicant build config
---------------------------
-Enable DPP and protected management frame in wpa_supplicant build config
-file
+Enable DPP in wpa_supplicant build config file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
hostapd build config
--------------------
-Enable DPP and protected management frame in hostapd build config file
+Enable DPP in hostapd build config file
-CONFIG_IEEE80211W=y
CONFIG_DPP=y
Configurator build config
-------------------------
-Any STA or AP device can act as a Configurator. Enable DPP and protected
-managment frames in build config. For an AP to act as Configurator,
-Interworking needs to be enabled. For wpa_supplicant it is not required.
+Any STA or AP device can act as a Configurator. Enable DPP in build
+config. For an AP to act as a Configurator, Interworking needs to be
+enabled for GAS. For wpa_supplicant it is not required.
CONFIG_INTERWORKING=y
@@ -92,39 +94,46 @@ To get key of Configurator
> dpp_configurator_get_key <id>
-How to configure an enrollee using Configurator
+How to configure an Enrollee using Configurator
-----------------------------------------------
-On enrollee side:
+On Enrollee side:
-Generate QR code for the device. Store the qr code id returned by the
+Generate QR code for the device. Store the QR code id returned by the
command.
-> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/operating-channel> key=<key of the device>
-(returns bootstrapping info id)
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device>
+(Returns bootstrapping info id. If the key parameter is not included, a new key
+is generated automatically. The MAC address is specified without octet
+separating colons. The channel list includes the possible channels on which the
+device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4
+GHz channel 1 on 2412 MHz.)
-Get QR Code of device using the bootstrap info id.
+Get URI for the QR Code of device using the bootstrap info id.
> dpp_bootstrap_get_uri <bootstrap-id>
-Make device listen to DPP request (The central frequency of channel 1 is
-2412) in case if enrollee is a client device.
+Make device listen to DPP request. The central frequency of the 2.4 GHz
+band channel 1 is 2412 MHz) in case the Enrollee is a client device. An
+AP as an Enrollee is listening on its operating channel.
> dpp_listen <frequency>
On Configurator side:
Enter the QR Code in the Configurator.
-> dpp_qr_code "<QR-Code-read-from-enrollee>"
+> dpp_qr_code "<URI-from-QR-Code-read-from-enrollee>"
On successfully adding QR Code, a bootstrapping info id is returned.
-Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
-AP. conf is sta-dpp if enrollee is a client)
-> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+Send provisioning request to Enrollee. (conf is ap-dpp if Enrollee is an
+AP. conf is sta-dpp if Enrollee is a client)
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id>
+or for legacy (PSK/SAE) provisioning for a station Enrollee:
+> dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump>
-The DPP values will be printed in the console. Save this values into the
-config file. If the enrollee is an AP, we need to manually write these
-values to the hostapd config file. If the enrollee is a client device,
+The DPP values will be printed in the console. Save these values into the
+config file. If the Enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the Enrollee is a client device,
these details can be automatically saved to config file using the
following command.
@@ -156,7 +165,7 @@ command to get DPP credentials.
> dpp_configurator_add
(returns configurator id)
-> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump>
Sample AP configuration files after provisioning
diff --git a/contrib/wpa/wpa_supplicant/README-HS20 b/contrib/wpa/wpa_supplicant/README-HS20
index 334287101c92..484e4cbf4724 100644
--- a/contrib/wpa/wpa_supplicant/README-HS20
+++ b/contrib/wpa/wpa_supplicant/README-HS20
@@ -78,7 +78,7 @@ hs20=1
# Parameters for controlling scanning
-# Homogenous ESS identifier
+# Homogeneous ESS identifier
# If this is set, scans will be used to request response only from BSSes
# belonging to the specified Homogeneous ESS. This is used only if interworking
# is enabled.
diff --git a/contrib/wpa/wpa_supplicant/android.config b/contrib/wpa/wpa_supplicant/android.config
index 6536c110a3ca..283f8eb0a995 100644
--- a/contrib/wpa/wpa_supplicant/android.config
+++ b/contrib/wpa/wpa_supplicant/android.config
@@ -273,10 +273,6 @@ CONFIG_L2_PACKET=linux
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -442,11 +438,7 @@ CONFIG_ANDROID_LOG=y
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
#CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -542,4 +534,12 @@ CONFIG_WIFI_DISPLAY=y
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/contrib/wpa/wpa_supplicant/ap.c b/contrib/wpa/wpa_supplicant/ap.c
index 4e3c2814d0f3..cdf0ed5c7b5f 100644
--- a/contrib/wpa/wpa_supplicant/ap.c
+++ b/contrib/wpa/wpa_supplicant/ap.c
@@ -44,7 +44,29 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211N
+#ifdef CONFIG_P2P
+static bool is_chanwidth160_supported(struct hostapd_hw_modes *mode,
+ struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax) {
+ struct he_capabilities *he_cap;
+
+ he_cap = &mode->he_capab[IEEE80211_MODE_AP];
+ if (he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G))
+ return true;
+ }
+#endif /* CONFIG_IEEE80211AX */
+ if (mode->vht_capab & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
+ return true;
+ return false;
+}
+#endif /* CONFIG_P2P */
+
+
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf,
@@ -54,39 +76,48 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
u8 center_chan = 0;
u8 channel = conf->channel;
#endif /* CONFIG_P2P */
+ u8 freq_seg_idx;
if (!conf->secondary_channel)
goto no_vht;
/* Use the maximum oper channel width if it's given. */
if (ssid->max_oper_chwidth)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth);
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
+ if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
+ }
if (!ssid->p2p_group) {
- if (!ssid->vht_center_freq1 ||
- conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ if (!ssid->vht_center_freq1)
goto no_vht;
ieee80211_freq_to_chan(ssid->vht_center_freq1,
- &conf->vht_oper_centr_freq_seg0_idx);
- wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
- conf->vht_oper_centr_freq_seg0_idx);
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg0_idx(conf, freq_seg_idx);
+
+ wpa_printf(MSG_DEBUG,
+ "VHT seg0 index %d and seg1 index %d for AP",
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf));
return;
}
#ifdef CONFIG_P2P
- switch (conf->vht_oper_chwidth) {
+ switch (hostapd_get_oper_chwidth(conf)) {
case CHANWIDTH_80MHZ:
case CHANWIDTH_80P80MHZ:
- center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel,
+ conf->op_class);
wpa_printf(MSG_DEBUG,
"VHT center channel %u for 80 or 80+80 MHz bandwidth",
center_chan);
break;
case CHANWIDTH_160MHZ:
- center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
+ conf->op_class);
wpa_printf(MSG_DEBUG,
"VHT center channel %u for 160 MHz bandwidth",
center_chan);
@@ -97,16 +128,26 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
* try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
* not supported.
*/
- conf->vht_oper_chwidth = CHANWIDTH_160MHZ;
- center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
- if (center_chan) {
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
+ ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+ conf->vht_oper_chwidth,
+ &conf->op_class,
+ &conf->channel);
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
+ conf->op_class);
+ if (center_chan && is_chanwidth160_supported(mode, conf)) {
wpa_printf(MSG_DEBUG,
"VHT center channel %u for auto-selected 160 MHz bandwidth",
center_chan);
} else {
- conf->vht_oper_chwidth = CHANWIDTH_80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+ ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+ conf->vht_oper_chwidth,
+ &conf->op_class,
+ &conf->channel);
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
- channel);
+ channel,
+ conf->op_class);
wpa_printf(MSG_DEBUG,
"VHT center channel %u for auto-selected 80 MHz bandwidth",
center_chan);
@@ -116,9 +157,9 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
if (!center_chan)
goto no_vht;
- conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ hostapd_set_oper_centr_freq_seg0_idx(conf, center_chan);
wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
- conf->vht_oper_centr_freq_seg0_idx);
+ hostapd_get_oper_centr_freq_seg0_idx(conf));
return;
#endif /* CONFIG_P2P */
@@ -126,30 +167,49 @@ no_vht:
wpa_printf(MSG_DEBUG,
"No VHT higher bandwidth support for the selected channel %d",
conf->channel);
- conf->vht_oper_centr_freq_seg0_idx =
- conf->channel + conf->secondary_channel * 2;
- conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ conf, conf->channel + conf->secondary_channel * 2);
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode hw_mode)
+{
+ struct hostapd_hw_modes *mode = NULL;
+ int i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ return mode;
}
-#endif /* CONFIG_IEEE80211N */
int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf)
{
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
-
+ conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+ ssid->max_oper_chwidth,
+ &conf->op_class,
+ &conf->channel);
+ /* ssid->max_oper_chwidth is not valid in all cases, so fall back to the
+ * less specific mechanism, if needed, at least for now */
+ if (conf->hw_mode == NUM_HOSTAPD_MODES)
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
ssid->frequency);
return -1;
}
- /* TODO: enable HT40 if driver supports it;
- * drop to 11b if driver does not support 11g */
-
-#ifdef CONFIG_IEEE80211N
/*
* Enable HT20 if the driver supports it, by setting conf->ieee80211n
* and a mask of allowed capabilities within conf->ht_capab.
@@ -158,17 +218,28 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
- int i, no_ht = 0;
+ int no_ht = 0;
wpa_printf(MSG_DEBUG,
"Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
ssid->frequency, conf->channel);
- for (i = 0; i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
- mode = &wpa_s->hw.modes[i];
- break;
- }
+ mode = wpa_supplicant_find_hw_mode(wpa_s, conf->hw_mode);
+
+ /* May drop to IEEE 802.11b if the driver does not support IEEE
+ * 802.11g */
+ if (!mode && conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ wpa_printf(MSG_INFO,
+ "Try downgrade to IEEE 802.11b as 802.11g is not supported by the current hardware");
+ mode = wpa_supplicant_find_hw_mode(wpa_s,
+ conf->hw_mode);
+ }
+
+ if (!mode) {
+ wpa_printf(MSG_ERROR,
+ "No match between requested and supported hw modes found");
+ return -1;
}
#ifdef CONFIG_HT_OVERRIDES
@@ -193,6 +264,14 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
ssid->ht40);
conf->ieee80211n = 1;
+
+ if (ssid->ht40 &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ conf->secondary_channel = ssid->ht40;
+ else
+ conf->secondary_channel = 0;
+
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
@@ -205,6 +284,16 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG,
"HT secondary channel offset %d for P2P group",
conf->secondary_channel);
+ } else if (ssid->p2p_group && conf->secondary_channel &&
+ conf->hw_mode != HOSTAPD_MODE_IEEE80211A) {
+ /* This ended up trying to configure invalid
+ * 2.4 GHz channels (e.g., HT40+ on channel 11)
+ * in some cases, so clear the secondary channel
+ * configuration now to avoid such cases that
+ * would lead to group formation failures. */
+ wpa_printf(MSG_DEBUG,
+ "Disable HT secondary channel for P2P group on 2.4 GHz");
+ conf->secondary_channel = 0;
}
#endif /* CONFIG_P2P */
@@ -234,16 +323,19 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
+ /* check this before VHT, because setting oper chan
+ * width and friends is the same call for HE and VHT
+ * and checks if conf->ieee8021ax == 1 */
+ if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].he_supported &&
+ ssid->he)
+ conf->ieee80211ax = 1;
+
if (mode->vht_capab && ssid->vht) {
conf->ieee80211ac = 1;
conf->vht_capab |= mode->vht_capab;
wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
}
-
- if (mode->he_capab[wpas_mode_to_ieee80211_mode(
- ssid->mode)].he_supported &&
- ssid->he)
- conf->ieee80211ax = 1;
}
}
@@ -269,7 +361,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
conf->no_pri_sec_switch = 1;
}
}
-#endif /* CONFIG_IEEE80211N */
return 0;
}
@@ -348,7 +439,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211AX */
bss->isolate = !wpa_s->conf->p2p_intra_bss;
+ bss->extended_key_id = wpa_s->conf->extended_key_id;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
+ bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
if (ssid->p2p_group) {
os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
@@ -381,7 +474,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
else
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->psk_set) {
+ if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+ } else if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
@@ -391,6 +486,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+#ifdef CONFIG_WEP
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -406,8 +502,37 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
+#endif /* CONFIG_WEP */
+ }
+#ifdef CONFIG_SAE
+ if (ssid->sae_password) {
+ struct sae_password_entry *pw;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN);
+ pw->password = os_strdup(ssid->sae_password);
+ if (!pw->password) {
+ os_free(pw);
+ return -1;
+ }
+ if (ssid->sae_password_id) {
+ pw->identifier = os_strdup(ssid->sae_password_id);
+ if (!pw->identifier) {
+ str_clear_free(pw->password);
+ os_free(pw);
+ return -1;
+ }
+ }
+
+ pw->next = bss->sae_passwords;
+ bss->sae_passwords = pw;
}
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
if (wpa_s->conf->go_interworking) {
wpa_printf(MSG_DEBUG,
"P2P: Enable Interworking with access_network_type: %d",
@@ -459,11 +584,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
bss->rsn_pairwise);
- if (bss->wpa && bss->ieee802_1x)
+ if (bss->wpa && bss->ieee802_1x) {
bss->ssid.security_policy = SECURITY_WPA;
- else if (bss->wpa)
+ } else if (bss->wpa) {
bss->ssid.security_policy = SECURITY_WPA_PSK;
- else if (bss->ieee802_1x) {
+#ifdef CONFIG_WEP
+ } else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
@@ -481,6 +607,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+#endif /* CONFIG_WEP */
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
@@ -500,10 +627,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_group_rekey = 86400;
}
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
bss->ieee80211w = ssid->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
bss->ocv = ssid->ocv;
@@ -577,6 +702,8 @@ no_wps:
bss->ftm_responder = wpa_s->conf->ftm_responder;
bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+ bss->transition_disable = ssid->transition_disable;
+
return 0;
}
@@ -747,9 +874,26 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
ssid->frequency = 2462; /* default channel 11 */
params.freq.freq = ssid->frequency;
+ if ((ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO) &&
+ ssid->enable_edmg) {
+ u8 primary_channel;
+
+ if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "EDMG: Failed to get the primary channel");
+ return -1;
+ }
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg, ssid->edmg_channel,
+ primary_channel, &params.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
+ else if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
params.key_mgmt_suite = wpa_s->key_mgmt;
@@ -796,7 +940,6 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
- hapd_iface->smps_modes = wpa_s->drv_smps_modes;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
@@ -812,6 +955,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
wpa_s->conf->wmm_ac_params,
sizeof(wpa_s->conf->wmm_ac_params));
+ os_memcpy(wpa_s->ap_iface->conf->tx_queue, wpa_s->conf->tx_queue,
+ sizeof(wpa_s->conf->tx_queue));
+
if (params.uapsd > 0) {
conf->bss[0]->wmm_enabled = 1;
conf->bss[0]->wmm_uapsd = 1;
@@ -885,6 +1031,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
+ wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
if (wpa_s->p2p_go_do_acs) {
@@ -1367,10 +1515,17 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
struct csa_settings *settings)
{
#ifdef NEED_AP_MLME
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = NULL;
+
+ if (wpa_s->ap_iface)
+ iface = wpa_s->ap_iface;
+ else if (wpa_s->ifmsh)
+ iface = wpa_s->ifmsh;
+
+ if (!iface || !iface->bss[0])
return -1;
- return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+ return hostapd_switch_channel(iface->bss[0], settings);
#else /* NEED_AP_MLME */
return -1;
#endif /* NEED_AP_MLME */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder.h b/contrib/wpa/wpa_supplicant/binder/binder.h
index 019e3275c5e2..6d7abb134894 100644
--- a/contrib/wpa/wpa_supplicant/binder/binder.h
+++ b/contrib/wpa/wpa_supplicant/binder/binder.h
@@ -17,7 +17,7 @@ extern "C" {
/**
* This is the binder RPC interface entry point to the wpa_supplicant core.
* This initializes the binder driver & BinderManager instance and then forwards
- * all the notifcations from the supplicant core to the BinderManager.
+ * all the notifications from the supplicant core to the BinderManager.
*/
struct wpas_binder_priv;
struct wpa_global;
diff --git a/contrib/wpa/wpa_supplicant/bss.c b/contrib/wpa/wpa_supplicant/bss.c
index 441529cb0fd5..e13783ce1995 100644
--- a/contrib/wpa/wpa_supplicant/bss.c
+++ b/contrib/wpa/wpa_supplicant/bss.c
@@ -19,18 +19,6 @@
#include "scan.h"
#include "bss.h"
-
-#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
-#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
-#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
-#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
-#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
-#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
-#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
-#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
-#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-
-
static void wpa_bss_set_hessid(struct wpa_bss *bss)
{
#ifdef CONFIG_INTERWORKING
@@ -351,10 +339,31 @@ static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
}
+static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+#ifdef CONFIG_P2P
+ u8 addr[ETH_ALEN];
+
+ if (os_memcmp(bss->bssid, wpa_s->pending_join_iface_addr,
+ ETH_ALEN) == 0)
+ return true;
+ if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) &&
+ p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 &&
+ os_memcmp(addr, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0)
+ return true;
+#endif /* CONFIG_P2P */
+ return false;
+}
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
+ if (is_p2p_pending_bss(wpa_s, bss))
+ return 1;
+
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid->ssid == NULL || ssid->ssid_len == 0)
continue;
@@ -443,7 +452,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
- os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
wpa_bss_set_hessid(bss);
if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
@@ -546,7 +555,7 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
changes |= WPA_BSS_MODE_CHANGED_FLAG;
if (old->ie_len == new_res->ie_len &&
- os_memcmp(old + 1, new_res + 1, old->ie_len) == 0)
+ os_memcmp(wpa_bss_ie_ptr(old), new_res + 1, old->ie_len) == 0)
return changes;
changes |= WPA_BSS_IES_CHANGED_FLAG;
@@ -567,8 +576,8 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
}
-static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
- const struct wpa_bss *bss)
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss)
{
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpas_notify_bss_freq_changed(wpa_s, bss->id);
@@ -670,7 +679,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#endif /* CONFIG_P2P */
if (bss->ie_len + bss->beacon_ie_len >=
res->ie_len + res->beacon_ie_len) {
- os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
} else {
@@ -691,7 +700,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_s->current_bss = nbss;
wpa_bss_update_pending_connect(wpa_s, bss, nbss);
bss = nbss;
- os_memcpy(bss + 1, res + 1,
+ os_memcpy(bss->ies, res + 1,
res->ie_len + res->beacon_ie_len);
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
@@ -906,7 +915,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
}
}
- wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
}
@@ -1038,23 +1047,30 @@ struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_P2P
/**
- * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
* @wpa_s: Pointer to wpa_supplicant data
* @dev_addr: P2P Device Address of the GO
* Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function tries to find the entry that has the most recent update. This
+ * can help in finding the correct entry in cases where the SSID of the P2P
+ * Device may have changed recently.
*/
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss, *found = NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
u8 addr[ETH_ALEN];
- if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
- addr) == 0 &&
- os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
- return bss;
+ if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
+ addr) != 0 ||
+ os_memcmp(addr, dev_addr, ETH_ALEN) != 0)
+ continue;
+ if (!found ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
}
- return NULL;
+ return found;
}
#endif /* CONFIG_P2P */
@@ -1110,7 +1126,22 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
*/
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
- return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
+ return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
+}
+
+
+/**
+ * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
+ * @bss: BSS table entry
+ * @ext: Information element extension identifier (WLAN_EID_EXT_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext)
+{
+ return get_ie_ext(wpa_bss_ie_ptr(bss), bss->ie_len, ext);
}
@@ -1125,18 +1156,15 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
*/
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
- pos = (const u8 *) (bss + 1);
- end = pos + bss->ie_len;
+ ies = wpa_bss_ie_ptr(bss);
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1158,22 +1186,20 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
if (bss->beacon_ie_len == 0)
return NULL;
- pos = (const u8 *) (bss + 1);
- pos += bss->ie_len;
- end = pos + bss->beacon_ie_len;
+ ies = wpa_bss_ie_ptr(bss);
+ ies += bss->ie_len;
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
+ bss->beacon_ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1200,16 +1226,21 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
if (buf == NULL)
return NULL;
- pos = (const u8 *) (bss + 1);
+ pos = wpa_bss_ie_ptr(bss);
end = pos + bss->ie_len;
while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
+ u8 ie, len;
+
+ ie = pos[0];
+ len = pos[1];
+ if (len > end - pos - 2)
break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
+ pos += 2;
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+ vendor_type == WPA_GET_BE32(pos))
+ wpabuf_put_data(buf, pos + 4, len - 4);
+ pos += len;
}
if (wpabuf_len(buf) == 0) {
@@ -1244,7 +1275,7 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
if (buf == NULL)
return NULL;
- pos = (const u8 *) (bss + 1);
+ pos = wpa_bss_ie_ptr(bss);
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
@@ -1330,7 +1361,7 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
#ifdef CONFIG_FILS
-const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
+const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss)
{
const u8 *ie;
@@ -1347,6 +1378,8 @@ const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
{
+ if (!bss)
+ return 0;
return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
capab);
}
diff --git a/contrib/wpa/wpa_supplicant/bss.h b/contrib/wpa/wpa_supplicant/bss.h
index 3ce8cd3f429a..4078b9b9d0a4 100644
--- a/contrib/wpa/wpa_supplicant/bss.h
+++ b/contrib/wpa/wpa_supplicant/bss.h
@@ -18,10 +18,22 @@ struct wpa_scan_res;
#define WPA_BSS_AUTHENTICATED BIT(4)
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+#define WPA_BSS_OWE_TRANSITION BIT(7)
+
+#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
+#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
+#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
+#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
+#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
+#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
+#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
+#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
+#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
struct wpa_bss_anqp_elem {
struct dl_list list;
u16 infoid;
+ bool protected_response; /* received in a protected GAS response */
struct wpabuf *payload;
};
@@ -110,8 +122,16 @@ struct wpa_bss {
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
+ u8 ies[];
};
+static inline const u8 * wpa_bss_ie_ptr(const struct wpa_bss *bss)
+{
+ return bss->ies;
+}
+
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss);
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
@@ -136,6 +156,7 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
u32 vendor_type);
@@ -147,7 +168,7 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
-const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
+const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss);
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
static inline int bss_is_dmg(const struct wpa_bss *bss)
@@ -168,7 +189,7 @@ static inline int bss_is_pbss(struct wpa_bss *bss)
static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
{
- if (bss != NULL && new_level < 0)
+ if (bss != NULL && new_level > -WPA_INVALID_NOISE && new_level < 0)
bss->level = new_level;
}
diff --git a/contrib/wpa/wpa_supplicant/bssid_ignore.c b/contrib/wpa/wpa_supplicant/bssid_ignore.c
new file mode 100644
index 000000000000..e37857798a02
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/bssid_ignore.c
@@ -0,0 +1,221 @@
+/*
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, 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 "wpa_supplicant_i.h"
+#include "bssid_ignore.h"
+
+/**
+ * wpa_bssid_ignore_get - Get the ignore list entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching entry for the BSSID or %NULL if not found
+ */
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return NULL;
+
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->was_recently_reconfigured) {
+ wpa_bssid_ignore_clear(wpa_s);
+ wpa_s->current_ssid->was_recently_reconfigured = false;
+ return NULL;
+ }
+
+ wpa_bssid_ignore_update(wpa_s);
+
+ e = wpa_s->bssid_ignore;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_bssid_ignore_add - Add an BSSID to the ignore list
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the ignore list
+ * Returns: Current ignore list count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the ignore list or increases the
+ * ignore count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This ignore list is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+ struct os_reltime now;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
+ os_get_reltime(&now);
+ if (e) {
+ e->start = now;
+ e->count++;
+ if (e->count > 5)
+ e->timeout_secs = 1800;
+ else if (e->count == 5)
+ e->timeout_secs = 600;
+ else if (e->count == 4)
+ e->timeout_secs = 120;
+ else if (e->count == 3)
+ e->timeout_secs = 60;
+ else
+ e->timeout_secs = 10;
+ wpa_printf(MSG_INFO, "BSSID " MACSTR
+ " ignore list count incremented to %d, ignoring for %d seconds",
+ MAC2STR(bssid), e->count, e->timeout_secs);
+ return e->count;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ os_memcpy(e->bssid, bssid, ETH_ALEN);
+ e->count = 1;
+ e->timeout_secs = 10;
+ e->start = now;
+ e->next = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = e;
+ wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR
+ " into ignore list, ignoring for %d seconds",
+ MAC2STR(bssid), e->timeout_secs);
+
+ return e->count;
+}
+
+
+/**
+ * wpa_bssid_ignore_del - Remove an BSSID from the ignore list
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be removed from the ignore list
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e, *prev = NULL;
+
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
+ e = wpa_s->bssid_ignore;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+ if (prev == NULL) {
+ wpa_s->bssid_ignore = e->next;
+ } else {
+ prev->next = e->next;
+ }
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list", MAC2STR(bssid));
+ os_free(e);
+ return 0;
+ }
+ prev = e;
+ e = e->next;
+ }
+ return -1;
+}
+
+
+/**
+ * wpa_bssid_ignore_is_listed - Check whether a BSSID is ignored temporarily
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be checked
+ * Returns: count if BSS is currently considered to be ignored, 0 otherwise
+ */
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bssid_ignore *e;
+ struct os_reltime now;
+
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
+ if (!e)
+ return 0;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &e->start, e->timeout_secs))
+ return 0;
+ return e->count;
+}
+
+
+/**
+ * wpa_bssid_ignore_clear - Clear the ignore list of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bssid_ignore *e, *prev;
+
+ e = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = NULL;
+ while (e) {
+ prev = e;
+ e = e->next;
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list (clear)", MAC2STR(prev->bssid));
+ os_free(prev);
+ }
+}
+
+
+/**
+ * wpa_bssid_ignore_update - Update the entries in the ignore list,
+ * deleting entries that have been expired for over an hour.
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bssid_ignore *e, *prev = NULL;
+ struct os_reltime now;
+
+ if (!wpa_s)
+ return;
+
+ e = wpa_s->bssid_ignore;
+ os_get_reltime(&now);
+ while (e) {
+ if (os_reltime_expired(&now, &e->start,
+ e->timeout_secs + 3600)) {
+ struct wpa_bssid_ignore *to_delete = e;
+
+ if (prev) {
+ prev->next = e->next;
+ e = prev->next;
+ } else {
+ wpa_s->bssid_ignore = e->next;
+ e = wpa_s->bssid_ignore;
+ }
+ wpa_printf(MSG_INFO, "Removed BSSID " MACSTR
+ " from ignore list (expired)",
+ MAC2STR(to_delete->bssid));
+ os_free(to_delete);
+ } else {
+ prev = e;
+ e = e->next;
+ }
+ }
+}
diff --git a/contrib/wpa/wpa_supplicant/bssid_ignore.h b/contrib/wpa/wpa_supplicant/bssid_ignore.h
new file mode 100644
index 000000000000..721b0e12665f
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/bssid_ignore.h
@@ -0,0 +1,33 @@
+/*
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSSID_IGNORE_H
+#define BSSID_IGNORE_H
+
+struct wpa_bssid_ignore {
+ struct wpa_bssid_ignore *next;
+ u8 bssid[ETH_ALEN];
+ int count;
+ /* Time of the most recent trigger to ignore this BSSID. */
+ struct os_reltime start;
+ /*
+ * Number of seconds after start that the entey will be considered
+ * valid.
+ */
+ int timeout_secs;
+};
+
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s);
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s);
+
+#endif /* BSSID_IGNORE_H */
diff --git a/contrib/wpa/wpa_supplicant/config.c b/contrib/wpa/wpa_supplicant/config.c
index 7a62f96d6e77..e8e9fd432618 100644
--- a/contrib/wpa/wpa_supplicant/config.c
+++ b/contrib/wpa/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, 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,7 @@
#include "utils/uuid.h"
#include "utils/ip_addr.h"
#include "common/ieee802_1x_defs.h"
+#include "common/sae.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -441,47 +442,99 @@ static char * wpa_config_write_bssid_hint(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_blacklist,
- &ssid->num_bssid_blacklist,
- "bssid_blacklist", 1, 1);
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist,
- "bssid_blacklist");
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
}
+
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_whitelist,
- &ssid->num_bssid_whitelist,
- "bssid_whitelist", 1, 1);
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist,
- "bssid_whitelist");
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
}
+
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifndef NO_CONFIG_WRITE
#endif /* NO_CONFIG_WRITE */
@@ -740,12 +793,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
@@ -910,7 +961,6 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
@@ -930,7 +980,6 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
@@ -1614,7 +1663,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
- if (name == NULL)
+ if (!name)
return -1;
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
@@ -1630,9 +1679,9 @@ static int wpa_config_parse_password(const struct parse_data *data,
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
- if (tmp == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to parse "
- "password.", line);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse password.", line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@@ -1650,13 +1699,14 @@ static int wpa_config_parse_password(const struct parse_data *data,
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
- "(expected 32 hex digits)", line);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid password hash length (expected 32 hex digits)",
+ line);
return -1;
}
hash = os_malloc(16);
- if (hash == NULL)
+ if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
@@ -1683,19 +1733,118 @@ static int wpa_config_parse_password(const struct parse_data *data,
}
+static int wpa_config_parse_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 *hash;
+
+ if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.machine_password)
+ return 1; /* Already unset */
+ wpa_printf(MSG_DEBUG,
+ "Unset configuration string 'machine_password'");
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = NULL;
+ ssid->eap.machine_password_len = 0;
+ return 0;
+ }
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+
+ if (!name)
+ return -1;
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) name;
+ ssid->eap.machine_password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (os_strncmp(value, "hash:", 5) != 0) {
+ char *tmp;
+ size_t res_len;
+
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse machine_password.",
+ line);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) tmp, res_len);
+
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) tmp;
+ ssid->eap.machine_password_len = res_len;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+ }
+
+
+ /* NtPasswordHash: hash:<32 hex digits> */
+ if (os_strlen(value + 5) != 2 * 16) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
+ line);
+ return -1;
+ }
+
+ hash = os_malloc(16);
+ if (!hash)
+ return -1;
+
+ if (hexstr2bin(value + 5, hash, 16)) {
+ os_free(hash);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
+ line);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+ if (ssid->eap.machine_password &&
+ ssid->eap.machine_password_len == 16 &&
+ os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = hash;
+ ssid->eap.machine_password_len = 16;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
+
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
- if (ssid->eap.password == NULL)
+ if (!ssid->eap.password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.password_len + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@@ -1709,7 +1858,7 @@ static char * wpa_config_write_password(const struct parse_data *data,
}
buf = os_malloc(5 + 32 + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
@@ -1717,10 +1866,50 @@ static char * wpa_config_write_password(const struct parse_data *data,
return buf;
}
+
+
+static char * wpa_config_write_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *buf;
+
+ if (!ssid->eap.machine_password)
+ return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ return wpa_config_write_string(
+ ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ }
+
+ buf = os_malloc(5 + 32 + 1);
+ if (!buf)
+ return NULL;
+
+ os_memcpy(buf, "hash:", 5);
+ wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
+
+ return buf;
+}
+
#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
+
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
const char *value, int idx)
{
@@ -1831,6 +2020,8 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
}
#endif /* NO_CONFIG_WRITE */
+#endif /* CONFIG_WEP */
+
#ifdef CONFIG_P2P
@@ -2141,23 +2332,24 @@ static char * wpa_config_write_peerkey(const struct parse_data *data,
/* STR: Define a string variable for an ASCII string; f = field name */
#ifdef NO_CONFIG_WRITE
#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
#else /* NO_CONFIG_WRITE */
#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
+ OFFSET(eap.m)
#endif /* NO_CONFIG_WRITE */
#define STR(f) _STR(f), NULL, NULL, NULL, 0
-#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
-#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
/* STR_LEN: Define a string variable with a separate variable for storing the
* data length. Unlike STR(), this can be used to store arbitrary binary data
* (i.e., even nul termination character). */
#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
-#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
-#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
@@ -2168,17 +2360,17 @@ static char * wpa_config_write_peerkey(const struct parse_data *data,
#ifdef NO_CONFIG_WRITE
#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
#else /* NO_CONFIG_WRITE */
#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
- OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
+ OFFSET(eap.m), (void *) 0
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
#define INT(f) _INT(f), NULL, NULL, 0
-#define INTe(f) _INTe(f), NULL, NULL, 0
+#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
/* INT_RANGE: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
@@ -2222,8 +2414,10 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
{ FUNC(bssid_hint) },
- { FUNC(bssid_blacklist) },
- { FUNC(bssid_whitelist) },
+ { FUNC(bssid_ignore) },
+ { FUNC(bssid_accept) },
+ { FUNC(bssid_blacklist) }, /* deprecated alias for bssid_ignore */
+ { FUNC(bssid_whitelist) }, /* deprecated alias for bssid_accept */
{ FUNC_KEY(psk) },
{ INT(mem_only_psk) },
{ STR_KEY(sae_password) },
@@ -2246,63 +2440,89 @@ static const struct parse_data ssid_fields[] = {
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
- { STR_LENe(identity) },
- { STR_LENe(anonymous_identity) },
- { STR_LENe(imsi_identity) },
+ { STR_LENe(identity, identity) },
+ { STR_LENe(anonymous_identity, anonymous_identity) },
+ { STR_LENe(imsi_identity, imsi_identity) },
+ { STR_LENe(machine_identity, machine_identity) },
{ FUNC_KEY(password) },
- { STRe(ca_cert) },
- { STRe(ca_path) },
- { STRe(client_cert) },
- { STRe(private_key) },
- { STR_KEYe(private_key_passwd) },
- { STRe(dh_file) },
- { STRe(subject_match) },
- { STRe(check_cert_subject) },
- { STRe(altsubject_match) },
- { STRe(domain_suffix_match) },
- { STRe(domain_match) },
- { STRe(ca_cert2) },
- { STRe(ca_path2) },
- { STRe(client_cert2) },
- { STRe(private_key2) },
- { STR_KEYe(private_key2_passwd) },
- { STRe(dh_file2) },
- { STRe(subject_match2) },
- { STRe(check_cert_subject2) },
- { STRe(altsubject_match2) },
- { STRe(domain_suffix_match2) },
- { STRe(domain_match2) },
- { STRe(phase1) },
- { STRe(phase2) },
- { STRe(pcsc) },
- { STR_KEYe(pin) },
- { STRe(engine_id) },
- { STRe(key_id) },
- { STRe(cert_id) },
- { STRe(ca_cert_id) },
- { STR_KEYe(pin2) },
- { STRe(engine2_id) },
- { STRe(key2_id) },
- { STRe(cert2_id) },
- { STRe(ca_cert2_id) },
- { INTe(engine) },
- { INTe(engine2) },
+ { FUNC_KEY(machine_password) },
+ { STRe(ca_cert, cert.ca_cert) },
+ { STRe(ca_path, cert.ca_path) },
+ { STRe(client_cert, cert.client_cert) },
+ { STRe(private_key, cert.private_key) },
+ { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
+ { STRe(dh_file, cert.dh_file) },
+ { STRe(subject_match, cert.subject_match) },
+ { STRe(check_cert_subject, cert.check_cert_subject) },
+ { STRe(altsubject_match, cert.altsubject_match) },
+ { STRe(domain_suffix_match, cert.domain_suffix_match) },
+ { STRe(domain_match, cert.domain_match) },
+ { STRe(ca_cert2, phase2_cert.ca_cert) },
+ { STRe(ca_path2, phase2_cert.ca_path) },
+ { STRe(client_cert2, phase2_cert.client_cert) },
+ { STRe(private_key2, phase2_cert.private_key) },
+ { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
+ { STRe(dh_file2, phase2_cert.dh_file) },
+ { STRe(subject_match2, phase2_cert.subject_match) },
+ { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
+ { STRe(altsubject_match2, phase2_cert.altsubject_match) },
+ { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
+ { STRe(domain_match2, phase2_cert.domain_match) },
+ { STRe(phase1, phase1) },
+ { STRe(phase2, phase2) },
+ { STRe(machine_phase2, machine_phase2) },
+ { STRe(pcsc, pcsc) },
+ { STR_KEYe(pin, cert.pin) },
+ { STRe(engine_id, cert.engine_id) },
+ { STRe(key_id, cert.key_id) },
+ { STRe(cert_id, cert.cert_id) },
+ { STRe(ca_cert_id, cert.ca_cert_id) },
+ { STR_KEYe(pin2, phase2_cert.pin) },
+ { STRe(engine_id2, phase2_cert.engine_id) },
+ { STRe(key_id2, phase2_cert.key_id) },
+ { STRe(cert_id2, phase2_cert.cert_id) },
+ { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
+ { INTe(engine, cert.engine) },
+ { INTe(engine2, phase2_cert.engine) },
+ { STRe(machine_ca_cert, machine_cert.ca_cert) },
+ { STRe(machine_ca_path, machine_cert.ca_path) },
+ { STRe(machine_client_cert, machine_cert.client_cert) },
+ { STRe(machine_private_key, machine_cert.private_key) },
+ { STR_KEYe(machine_private_key_passwd,
+ machine_cert.private_key_passwd) },
+ { STRe(machine_dh_file, machine_cert.dh_file) },
+ { STRe(machine_subject_match, machine_cert.subject_match) },
+ { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
+ { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
+ { STRe(machine_domain_suffix_match,
+ machine_cert.domain_suffix_match) },
+ { STRe(machine_domain_match, machine_cert.domain_match) },
+ { STR_KEYe(machine_pin, machine_cert.pin) },
+ { STRe(machine_engine_id, machine_cert.engine_id) },
+ { STRe(machine_key_id, machine_cert.key_id) },
+ { STRe(machine_cert_id, machine_cert.cert_id) },
+ { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
+ { INTe(machine_engine, machine_cert.engine) },
+ { INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
- { INTe(sim_num) },
- { STRe(openssl_ciphers) },
- { INTe(erp) },
+ { INTe(sim_num, sim_num) },
+ { STRe(openssl_ciphers, openssl_ciphers) },
+ { INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
{ FUNC_KEY(wep_key2) },
{ FUNC_KEY(wep_key3) },
{ INT(wep_tx_keyidx) },
+#endif /* CONFIG_WEP */
{ INT(priority) },
#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
- { STRe(pac_file) },
- { INTe(fragment_size) },
- { INTe(ocsp) },
+ { STRe(pac_file, pac_file) },
+ { INTe(fragment_size, fragment_size) },
+ { INTe(ocsp, cert.ocsp) },
+ { INTe(ocsp2, phase2_cert.ocsp) },
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
{ INT_RANGE(mode, 0, 5) },
@@ -2314,16 +2534,16 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
-#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
{ FUNC(ocv) },
#endif /* CONFIG_OCV */
{ FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
- { INT_RANGE(frequency, 0, 65000) },
+ { INT_RANGE(frequency, 0, 70200) },
{ INT_RANGE(fixed_freq, 0, 1) },
+ { INT_RANGE(enable_edmg, 0, 1) },
+ { INT_RANGE(edmg_channel, 9, 13) },
#ifdef CONFIG_ACS
{ INT_RANGE(acs, 0, 1) },
#endif /* CONFIG_ACS */
@@ -2335,6 +2555,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
{ INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2377,6 +2598,9 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
{ INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ { INT_RANGE(disable_he, 0, 1)},
+#endif /* CONFIG_HE_OVERRIDES */
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
{ INT(beacon_int) },
@@ -2403,11 +2627,17 @@ static const struct parse_data ssid_fields[] = {
{ STR_LEN(dpp_netaccesskey) },
{ INT(dpp_netaccesskey_expiry) },
{ STR_LEN(dpp_csign) },
+ { STR_LEN(dpp_pp_key) },
+ { INT_RANGE(dpp_pfs, 0, 2) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(owe_ptk_workaround, 0, 1) },
{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
+ { INT_RANGE(beacon_prot, 0, 1) },
+ { INT_RANGE(transition_disable, 0, 255) },
+ { INT_RANGE(sae_pk, 0, 2) },
};
#undef OFFSET
@@ -2443,7 +2673,7 @@ static const struct parse_data ssid_fields[] = {
int wpa_config_add_prio_network(struct wpa_config *config,
struct wpa_ssid *ssid)
{
- int prio;
+ size_t prio;
struct wpa_ssid *prev, **nlist;
/*
@@ -2514,48 +2744,44 @@ int wpa_config_update_prio_list(struct wpa_config *config)
#ifdef IEEE8021X_EAPOL
+
+static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
+{
+ os_free(cert->ca_cert);
+ os_free(cert->ca_path);
+ os_free(cert->client_cert);
+ os_free(cert->private_key);
+ str_clear_free(cert->private_key_passwd);
+ os_free(cert->dh_file);
+ os_free(cert->subject_match);
+ os_free(cert->check_cert_subject);
+ os_free(cert->altsubject_match);
+ os_free(cert->domain_suffix_match);
+ os_free(cert->domain_match);
+ str_clear_free(cert->pin);
+ os_free(cert->engine_id);
+ os_free(cert->key_id);
+ os_free(cert->cert_id);
+ os_free(cert->ca_cert_id);
+}
+
+
static void eap_peer_config_free(struct eap_peer_config *eap)
{
os_free(eap->eap_methods);
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
- os_free(eap->ca_cert);
- os_free(eap->ca_path);
- os_free(eap->client_cert);
- os_free(eap->private_key);
- str_clear_free(eap->private_key_passwd);
- os_free(eap->dh_file);
- os_free(eap->subject_match);
- os_free(eap->check_cert_subject);
- os_free(eap->altsubject_match);
- os_free(eap->domain_suffix_match);
- os_free(eap->domain_match);
- os_free(eap->ca_cert2);
- os_free(eap->ca_path2);
- os_free(eap->client_cert2);
- os_free(eap->private_key2);
- str_clear_free(eap->private_key2_passwd);
- os_free(eap->dh_file2);
- os_free(eap->subject_match2);
- os_free(eap->check_cert_subject2);
- os_free(eap->altsubject_match2);
- os_free(eap->domain_suffix_match2);
- os_free(eap->domain_match2);
+ bin_clear_free(eap->machine_password, eap->machine_password_len);
+ eap_peer_config_free_cert(&eap->cert);
+ eap_peer_config_free_cert(&eap->phase2_cert);
+ eap_peer_config_free_cert(&eap->machine_cert);
os_free(eap->phase1);
os_free(eap->phase2);
+ os_free(eap->machine_phase2);
os_free(eap->pcsc);
- str_clear_free(eap->pin);
- os_free(eap->engine_id);
- os_free(eap->key_id);
- os_free(eap->cert_id);
- os_free(eap->ca_cert_id);
- os_free(eap->key2_id);
- os_free(eap->cert2_id);
- os_free(eap->ca_cert2_id);
- str_clear_free(eap->pin2);
- os_free(eap->engine2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
@@ -2563,6 +2789,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
str_clear_free(eap->external_sim_resp);
os_free(eap->openssl_ciphers);
}
+
#endif /* IEEE8021X_EAPOL */
@@ -2590,8 +2817,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
- os_free(ssid->bssid_blacklist);
- os_free(ssid->bssid_whitelist);
+ os_free(ssid->bssid_ignore);
+ os_free(ssid->bssid_accept);
#ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */
@@ -2604,11 +2831,15 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->dpp_connector);
bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
os_free(ssid->dpp_csign);
+ os_free(ssid->dpp_pp_key);
while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
list))) {
dl_list_del(&psk->list);
bin_clear_free(psk, sizeof(*psk));
}
+#ifdef CONFIG_SAE
+ sae_deinit_pt(ssid->pt);
+#endif /* CONFIG_SAE */
bin_clear_free(ssid, sizeof(*ssid));
}
@@ -2713,6 +2944,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->p2p_no_go_freq.range);
os_free(config->autoscan);
os_free(config->freq_list);
+ os_free(config->initial_freq_list);
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
@@ -2727,6 +2959,8 @@ void wpa_config_free(struct wpa_config *config)
#ifdef CONFIG_MBO
os_free(config->non_pref_chan);
#endif /* CONFIG_MBO */
+ os_free(config->dpp_name);
+ os_free(config->dpp_mud_url);
os_free(config);
}
@@ -2856,8 +3090,11 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ssid->ht = 1;
+ ssid->vht = 1;
+ ssid->he = 1;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -2901,9 +3138,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->vht_tx_mcs_nss_8 = -1;
#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
@@ -2948,6 +3183,15 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
ret = -1;
}
+#ifdef CONFIG_SAE
+ if (os_strcmp(var, "ssid") == 0 ||
+ os_strcmp(var, "psk") == 0 ||
+ os_strcmp(var, "sae_password") == 0 ||
+ os_strcmp(var, "sae_password_id") == 0) {
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ }
+#endif /* CONFIG_SAE */
break;
}
if (i == NUM_SSID_FIELDS) {
@@ -2957,6 +3201,7 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
ret = -1;
}
+ ssid->was_recently_reconfigured = true;
return ret;
}
@@ -4070,6 +4315,8 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name)
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
struct wpa_config *config;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
@@ -4077,9 +4324,20 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
- { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ { aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
+ const struct hostapd_tx_queue_params txq_bk =
+ { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+ const struct hostapd_tx_queue_params txq_be =
+ { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
+ const struct hostapd_tx_queue_params txq_vi =
+ { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
+ const struct hostapd_tx_queue_params txq_vo =
+ { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+ (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
+
+#undef ecw2cw
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -4105,15 +4363,21 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->ap_isolate = DEFAULT_AP_ISOLATE;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+ config->scan_res_valid_for_connect = DEFAULT_SCAN_RES_VALID_FOR_CONNECT;
config->wmm_ac_params[0] = ac_be;
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
+ config->tx_queue[0] = txq_vo;
+ config->tx_queue[1] = txq_vi;
+ config->tx_queue[2] = txq_be;
+ config->tx_queue[3] = txq_bk;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+ config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
#ifdef CONFIG_MBO
config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -4139,7 +4403,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
*/
void wpa_config_debug_dump_networks(struct wpa_config *config)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < config->num_prio; prio++) {
@@ -4157,13 +4421,31 @@ void wpa_config_debug_dump_networks(struct wpa_config *config)
#endif /* CONFIG_NO_STDOUT_DEBUG */
+/**
+ * Structure for global configuration parsing. This data is used to implement a
+ * generic parser for the global interface configuration. The table of variables
+ * is defined below in this file (global_fields[]).
+ */
struct global_parse_data {
+ /* Configuration variable name */
char *name;
+
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct global_parse_data *data,
struct wpa_config *config, int line, const char *value);
+
+ /* Getter function to print the variable in text format to buf. */
int (*get)(const char *name, struct wpa_config *config, long offset,
char *buf, size_t buflen, int pretty_print);
+
+ /* Variable specific parameters for the parser. */
void *param1, *param2, *param3;
+
+ /* Indicates which configuration variable has changed. */
unsigned int changed_flag;
};
@@ -4174,6 +4456,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
{
int val, *dst;
char *end;
+ bool same;
dst = (int *) (((u8 *) config) + (long) data->param1);
val = strtol(pos, &end, 0);
@@ -4182,6 +4465,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
line, pos);
return -1;
}
+ same = *dst == val;
*dst = val;
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
@@ -4202,7 +4486,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
return -1;
}
- return 0;
+ return same;
}
@@ -4210,7 +4494,7 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
+ size_t len, prev_len;
char **dst, *tmp;
len = os_strlen(pos);
@@ -4234,11 +4518,20 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
return -1;
}
+ dst = (char **) (((u8 *) config) + (long) data->param1);
+ if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+
+ /* No change to the previously configured value */
+ if (*dst && prev_len == len && os_memcmp(*dst, pos, len) == 0)
+ return 1;
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
- dst = (char **) (((u8 *) config) + (long) data->param1);
os_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
@@ -4279,6 +4572,10 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
return -1;
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+ if (wpabuf_cmp(*dst, tmp) == 0) {
+ wpabuf_free(tmp);
+ return 1;
+ }
wpabuf_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s", data->name);
@@ -4306,6 +4603,26 @@ static int wpa_config_process_freq_list(const struct global_parse_data *data,
}
+static int
+wpa_config_process_initial_freq_list(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *value)
+{
+ int *freqs;
+
+ freqs = wpa_config_parse_int_array(value);
+ if (!freqs)
+ return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+ os_free(config->initial_freq_list);
+ config->initial_freq_list = freqs;
+ return 0;
+}
+
+
#ifdef CONFIG_P2P
static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
struct wpa_config *config, int line,
@@ -4320,6 +4637,8 @@ static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
return -1;
dst = (u32 *) (((u8 *) config) + (long) data->param1);
+ if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
+ return 1;
os_memcpy(dst, &addr.u.v4.s_addr, 4);
wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
WPA_GET_BE32((u8 *) dst));
@@ -4337,6 +4656,8 @@ static int wpa_config_process_country(const struct global_parse_data *data,
wpa_printf(MSG_DEBUG, "Invalid country set");
return -1;
}
+ if (pos[0] == config->country[0] && pos[1] == config->country[1])
+ return 1;
config->country[0] = pos[0];
config->country[1] = pos[1];
wpa_printf(MSG_DEBUG, "country='%c%c'",
@@ -4470,7 +4791,7 @@ static int wpa_config_process_p2p_pref_chan(
struct wpa_config *config, int line, const char *pos)
{
struct p2p_channel *pref = NULL, *n;
- unsigned int num = 0;
+ size_t num = 0;
const char *pos2;
u8 op_class, chan;
@@ -4721,7 +5042,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(eapol_version, 1, 2), 0 },
#endif /* CONFIG_MACSEC */
{ INT(ap_scan), 0 },
- { FUNC(bgscan), 0 },
+ { FUNC(bgscan), CFG_CHANGED_BGSCAN },
#ifdef CONFIG_MESH
{ INT(user_mpm), 0 },
{ INT_RANGE(max_peer_links, 0, 255), 0 },
@@ -4782,6 +5103,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
{ INT(p2p_go_he), 0 },
+ { INT(p2p_go_edmg), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4794,6 +5116,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(p2p_device_random_mac_addr), 0 },
{ FUNC(p2p_device_persistent_mac_addr), 0 },
{ INT(p2p_interface_random_mac_addr), 0 },
+ { INT(p2p_6ghz_disable), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -4828,12 +5151,16 @@ static const struct global_parse_data global_fields[] = {
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
+ { INT_RANGE(sae_pwe, 0, 3), 0 },
+ { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
{ FUNC(ap_vendor_elements), 0 },
{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
{ FUNC(freq_list), 0 },
+ { FUNC(initial_freq_list), 0},
{ INT(scan_cur_freq), 0 },
+ { INT(scan_res_valid_for_connect), 0},
{ INT(sched_scan_interval), 0 },
{ INT(sched_scan_start_delay), 0 },
{ INT(tdls_external_control), 0},
@@ -4867,11 +5194,23 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
+#ifdef CONFIG_DPP
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { STR(dpp_name), 0 },
+ { STR(dpp_mud_url), 0 },
+#endif /* CONFIG_DPP */
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
#ifdef CONFIG_WNM
{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
+ { INT_RANGE(extended_key_id, 0, 1), 0 },
#endif /* CONFIG_WNM */
+ { INT_RANGE(wowlan_disconnect_on_deinit, 0, 1), 0},
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ { INT_RANGE(force_kdk_derivation, 0, 1), 0 },
+ { INT_RANGE(pasn_corrupt_mic, 0, 1), 0 },
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
};
#undef FUNC
@@ -4947,6 +5286,19 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
}
+/**
+ * wpa_config_process_global - Set a variable in global configuration
+ * @config: Pointer to global configuration data
+ * @pos: Name and value in the format "{name}={value}"
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success with a possible change in value, 1 on success with no
+ * change to previously configured value, or -1 on failure
+ *
+ * This function can be used to set global configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{
size_t i;
@@ -4959,11 +5311,14 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
pos[flen] != '=')
continue;
- if (field->parser(field, config, line, pos + flen + 1)) {
+ ret = field->parser(field, config, line, pos + flen + 1);
+ if (ret < 0) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse '%s'.", line, pos);
ret = -1;
}
+ if (ret == 1)
+ break;
if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
@@ -4971,6 +5326,26 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
}
if (i == NUM_GLOBAL_FIELDS) {
#ifdef CONFIG_AP
+ if (os_strncmp(pos, "tx_queue_", 9) == 0) {
+ char *tmp = os_strchr(pos, '=');
+
+ if (!tmp) {
+ if (line < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid line %s",
+ line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_tx_queue(config->tx_queue, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid TX queue item",
+ line);
+ return -1;
+ }
+ }
+
if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
char *tmp = os_strchr(pos, '=');
if (tmp == NULL) {
@@ -4987,6 +5362,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
"AC item", line);
return -1;
}
+ return ret;
}
#endif /* CONFIG_AP */
if (line < 0)
diff --git a/contrib/wpa/wpa_supplicant/config.h b/contrib/wpa/wpa_supplicant/config.h
index 6a297ecfe5bd..68679c6e380a 100644
--- a/contrib/wpa/wpa_supplicant/config.h
+++ b/contrib/wpa/wpa_supplicant/config.h
@@ -44,6 +44,8 @@
#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
#define DEFAULT_OCE_SUPPORT OCE_STA
+#define DEFAULT_EXTENDED_KEY_ID 0
+#define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5
#include "config_ssid.h"
#include "wps/wps.h"
@@ -332,7 +334,7 @@ struct wpa_cred {
*/
unsigned int max_bss_load;
- unsigned int num_req_conn_capab;
+ size_t num_req_conn_capab;
u8 *req_conn_capab_proto;
int **req_conn_capab_port;
@@ -375,6 +377,7 @@ struct wpa_cred {
#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
#define CFG_CHANGED_DISABLE_BTM BIT(19)
+#define CFG_CHANGED_BGSCAN BIT(20)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -403,7 +406,7 @@ struct wpa_config {
* This indicates how many per-priority network lists are included in
* pssid.
*/
- int num_prio;
+ size_t num_prio;
/**
* cred - Head of the credential list
@@ -648,7 +651,7 @@ struct wpa_config {
* This variable control whether wpa_supplicant is allow to re-write
* its configuration with wpa_config_write(). If this is zero,
* configuration data is only changed in memory and the external data
- * is not overriden. If this is non-zero, wpa_supplicant will update
+ * is not overridden. If this is non-zero, wpa_supplicant will update
* the configuration data (e.g., a file) whenever configuration is
* changed. This update may replace the old configuration which can
* remove comments from it in case of a text file configuration.
@@ -778,6 +781,8 @@ struct wpa_config {
int p2p_ignore_shared_freq;
int p2p_optimize_listen_chan;
+ int p2p_6ghz_disable;
+
struct wpabuf *wps_vendor_ext_m1;
#define MAX_WPS_VENDOR_EXT 10
@@ -913,6 +918,19 @@ struct wpa_config {
int *freq_list;
/**
+ * initial_freq_list - like freq_list but for initial scan
+ *
+ * This is an optional zero-terminated array of frequencies in
+ * megahertz (MHz) to allow for narrowing scanning range when
+ * the application is started.
+ *
+ * This can be used to speed up initial connection time if the
+ * channel is known ahead of time, without limiting the scanned
+ * frequencies during normal use.
+ */
+ int *initial_freq_list;
+
+ /**
* scan_cur_freq - Whether to scan only the current channel
*
* If true, attempt to scan only the current channel if any other
@@ -921,6 +939,15 @@ struct wpa_config {
int scan_cur_freq;
/**
+ * scan_res_valid_for_connect - Seconds scans are valid for association
+ *
+ * This configures the number of seconds old scan results are considered
+ * valid for association. When scan results are older than this value
+ * a new scan is triggered prior to the association.
+ */
+ int scan_res_valid_for_connect;
+
+ /**
* changed_parameters - Bitmap of changed parameters since last update
*/
unsigned int changed_parameters;
@@ -973,7 +1000,7 @@ struct wpa_config {
int go_venue_type;
/**
- * hessid - Homogenous ESS identifier
+ * hessid - Homogeneous ESS identifier
*
* If this is set (any octet is non-zero), scans will be used to
* request response only from BSSes belonging to the specified
@@ -1057,6 +1084,7 @@ struct wpa_config {
int p2p_go_max_inactivity;
struct hostapd_wmm_ac_params wmm_ac_params[4];
+ struct hostapd_tx_queue_params tx_queue[4];
/**
* auto_interworking - Whether to use network selection automatically
@@ -1090,6 +1118,16 @@ struct wpa_config {
int p2p_go_vht;
/**
+ * p2p_go_edmg - Default mode for EDMG enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_edmg;
+
+ /**
* p2p_go_he - Default mode for 11ax HE enable when operating as GO
*
* This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
@@ -1165,6 +1203,19 @@ struct wpa_config {
int *sae_groups;
/**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
+ * sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
+ */
+ int sae_pmkid_in_assoc;
+
+ /**
* dtim_period - Default DTIM period in Beacon intervals
*
* This parameter can be used to set the default value for network
@@ -1492,6 +1543,16 @@ struct wpa_config {
int dpp_config_processing;
/**
+ * dpp_name - Name for Enrollee's DPP Configuration Request
+ */
+ char *dpp_name;
+
+ /**
+ * dpp_mud_url - MUD URL for Enrollee's DPP Configuration Request
+ */
+ char *dpp_mud_url;
+
+ /**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
@@ -1503,9 +1564,31 @@ struct wpa_config {
/**
* p2p_device_random_mac_addr - P2P Device MAC address policy default
*
- * 0 = use permanent MAC address
+ * 0 = use permanent MAC address (the one set by default by the device
+ * driver). Notice that, if the device driver is configured to
+ * always use random MAC addresses, this flag breaks reinvoking a
+ * persistent group, so flags 1 or 2 should be used instead with
+ * such drivers if persistent groups are used.
* 1 = use random MAC address on creating the interface if there is no
- * persistent groups.
+ * persistent group. Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used to change the MAC address of the P2P Device interface. With
+ * no persistent group, the random MAC address is created by
+ * wpa_supplicant, changing the one set by the device driver.
+ * The device driver shall support SIOCGIFFLAGS/SIOCSIFFLAGS ioctl
+ * interface control operations.
+ * 2 = this flag should be used when the device driver uses random MAC
+ * addresses by default when a P2P Device interface is created.
+ * If p2p_device_persistent_mac_addr is set, use this MAC address
+ * on creating the P2P Device interface. If not set, use the
+ * default method adopted by the device driver (e.g., random MAC
+ * address). Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used in place of the default address set by the device driver.
+ * (This option does not need support of SIOCGIFFLAGS/SIOCSIFFLAGS
+ * ioctl interface control operations and uses NL80211_ATTR_MAC).
*
* By default, permanent MAC address is used.
*/
@@ -1537,6 +1620,40 @@ struct wpa_config {
* By default BSS transition management is enabled
*/
int disable_btm;
+
+ /**
+ * extended_key_id - Extended Key ID support
+ *
+ * IEEE Std 802.11-2016 optionally allows to use Key ID 0 and 1 for PTK
+ * keys with Extended Key ID.
+ *
+ * 0 = don't use Extended Key ID
+ * 1 = use Extended Key ID when possible
+ */
+ int extended_key_id;
+
+ /**
+ * wowlan_disconnect_on_deinit - Trigger disconnect on wpa_supplicant
+ * interface deinit even if the driver has enabled WoWLAN.
+ *
+ * 0 = Do not disconnect
+ * 1 = Trigger disconnection
+ */
+ int wowlan_disconnect_on_deinit;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+
+ /* If set, corrupt the MIC in the 3rd Authentication frame of PASN */
+ int pasn_corrupt_mic;
+
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN*/
};
diff --git a/contrib/wpa/wpa_supplicant/config_file.c b/contrib/wpa/wpa_supplicant/config_file.c
index 77c326df54de..a535e3f08aad 100644
--- a/contrib/wpa/wpa_supplicant/config_file.c
+++ b/contrib/wpa/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,105 +23,7 @@
#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
#include "eap_peer/eap.h"
-
-
-static int newline_terminated(const char *buf, size_t buflen)
-{
- size_t len = os_strlen(buf);
- if (len == 0)
- return 0;
- if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
- buf[len - 1] != '\n')
- return 0;
- return 1;
-}
-
-
-static void skip_line_end(FILE *stream)
-{
- char buf[100];
- while (fgets(buf, sizeof(buf), stream)) {
- buf[sizeof(buf) - 1] = '\0';
- if (newline_terminated(buf, sizeof(buf)))
- return;
- }
-}
-
-
-/**
- * wpa_config_get_line - Read the next configuration file line
- * @s: Buffer for the line
- * @size: The buffer length
- * @stream: File stream to read from
- * @line: Pointer to a variable storing the file line number
- * @_pos: Buffer for the pointer to the beginning of data on the text line or
- * %NULL if not needed (returned value used instead)
- * Returns: Pointer to the beginning of data on the text line or %NULL if no
- * more text lines are available.
- *
- * This function reads the next non-empty line from the configuration file and
- * removes comments. The returned string is guaranteed to be null-terminated.
- */
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
- char **_pos)
-{
- char *pos, *end, *sstart;
-
- while (fgets(s, size, stream)) {
- (*line)++;
- s[size - 1] = '\0';
- if (!newline_terminated(s, size)) {
- /*
- * The line was truncated - skip rest of it to avoid
- * confusing error messages.
- */
- wpa_printf(MSG_INFO, "Long line in configuration file "
- "truncated");
- skip_line_end(stream);
- }
- pos = s;
-
- /* Skip white space from the beginning of line. */
- while (*pos == ' ' || *pos == '\t' || *pos == '\r')
- pos++;
-
- /* Skip comment lines and empty lines */
- if (*pos == '#' || *pos == '\n' || *pos == '\0')
- continue;
-
- /*
- * Remove # comments unless they are within a double quoted
- * string.
- */
- sstart = os_strchr(pos, '"');
- if (sstart)
- sstart = os_strrchr(sstart + 1, '"');
- if (!sstart)
- sstart = pos;
- end = os_strchr(sstart, '#');
- if (end)
- *end-- = '\0';
- else
- end = pos + os_strlen(pos) - 1;
-
- /* Remove trailing white space. */
- while (end > pos &&
- (*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r'))
- *end-- = '\0';
-
- if (*pos == '\0')
- continue;
-
- if (_pos)
- *_pos = pos;
- return pos;
- }
-
- if (_pos)
- *_pos = NULL;
- return NULL;
-}
+#include "utils/config.h"
static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
@@ -213,8 +115,22 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
}
}
- if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+ if (wpa_config_set(ssid, pos, pos2, *line) < 0) {
+#ifndef CONFIG_WEP
+ if (os_strcmp(pos, "wep_key0") == 0 ||
+ os_strcmp(pos, "wep_key1") == 0 ||
+ os_strcmp(pos, "wep_key2") == 0 ||
+ os_strcmp(pos, "wep_key3") == 0 ||
+ os_strcmp(pos, "wep_tx_keyidx") == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unsupported WEP parameter",
+ *line);
+ ssid->disabled = 1;
+ continue;
+ }
+#endif /* CONFIG_WEP */
errors++;
+ }
}
if (!end) {
@@ -296,7 +212,7 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
{
struct wpa_config_blob *blob;
char buf[256], *pos;
- unsigned char *encoded = NULL, *nencoded;
+ char *encoded = NULL, *nencoded;
int end = 0;
size_t encoded_len = 0, len;
@@ -653,6 +569,7 @@ static void write_eap(FILE *f, struct wpa_ssid *ssid)
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
@@ -667,6 +584,7 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
os_free(value);
}
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_P2P
@@ -741,20 +659,18 @@ static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
- int i;
-
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
-#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(f, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
write_bssid(f, ssid);
write_bssid_hint(f, ssid);
- write_str(f, "bssid_blacklist", ssid);
- write_str(f, "bssid_whitelist", ssid);
+ write_str(f, "bssid_ignore", ssid);
+ write_str(f, "bssid_accept", ssid);
write_psk(f, ssid);
INT(mem_only_psk);
STR(sae_password);
@@ -774,7 +690,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(identity);
STR(anonymous_identity);
STR(imsi_identity);
+ STR(machine_identity);
STR(password);
+ STR(machine_password);
STR(ca_cert);
STR(ca_path);
STR(client_cert);
@@ -797,8 +715,20 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
+ STR(machine_ca_cert);
+ STR(machine_ca_path);
+ STR(machine_client_cert);
+ STR(machine_private_key);
+ STR(machine_private_key_passwd);
+ STR(machine_dh_file);
+ STR(machine_subject_match);
+ STR(machine_check_cert_subject);
+ STR(machine_altsubject_match);
+ STR(machine_domain_suffix_match);
+ STR(machine_domain_match);
STR(phase1);
STR(phase2);
+ STR(machine_phase2);
STR(pcsc);
STR(pin);
STR(engine_id);
@@ -810,26 +740,37 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
+ INTe(machine_engine, machine_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
STR(openssl_ciphers);
- INTe(erp);
+ INTe(erp, erp);
#endif /* IEEE8021X_EAPOL */
- for (i = 0; i < 4; i++)
- write_wep_key(f, i, ssid);
- INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(f, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
INT(priority);
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
- INTe(ocsp);
- INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INTe(ocsp, cert.ocsp);
+ INTe(ocsp2, phase2_cert.ocsp);
+ INTe(machine_ocsp, machine_cert.ocsp);
+ INT_DEFe(sim_num, sim_num, DEFAULT_USER_SELECTED_SIM);
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -837,19 +778,18 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(mixed_cell);
- INT(vht);
+ INT_DEF(vht, 1);
INT_DEF(ht, 1);
INT(ht40);
+ INT_DEF(he, 1);
INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
INT(vht_center_freq1);
INT(vht_center_freq2);
INT(pbss);
INT(wps_disabled);
INT(fils_dh_group);
-#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
write_go_p2p_dev_addr(f, ssid);
@@ -883,6 +823,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(wpa_deny_ptk0_rekey);
INT(group_rekey);
INT(ignore_broadcast_ssid);
#ifdef CONFIG_DPP
@@ -890,11 +831,17 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dpp_netaccesskey);
INT(dpp_netaccesskey_expiry);
STR(dpp_csign);
+ STR(dpp_pp_key);
+ INT(dpp_pfs);
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
+ INT(owe_ptk_workaround);
INT(multi_ap_backhaul_sta);
INT(ft_eap_pmksa_caching);
+ INT(beacon_prot);
+ INT(transition_disable);
+ INT(sae_pk);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -929,6 +876,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(vht_tx_mcs_nss_7, -1);
INT_DEF(vht_tx_mcs_nss_8, -1);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ INT(disable_he);
+#endif /* CONFIG_HE_OVERRIDES */
#undef STR
#undef INT
@@ -1081,7 +1031,7 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(blob->data, blob->len, NULL);
if (encoded == NULL)
@@ -1270,6 +1220,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
if (config->p2p_go_he)
fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
+ if (config->p2p_go_edmg)
+ fprintf(f, "p2p_go_edmg=%d\n", config->p2p_go_edmg);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1285,6 +1237,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
fprintf(f, "p2p_go_freq_change_policy=%u\n",
config->p2p_go_freq_change_policy);
+
+ if (config->p2p_6ghz_disable)
+ fprintf(f, "p2p_6ghz_disable=%d\n", config->p2p_6ghz_disable);
+
if (WPA_GET_BE32(config->ip_addr_go))
fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
config->ip_addr_go[0], config->ip_addr_go[1],
@@ -1390,6 +1346,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "\n");
}
+ if (config->sae_pwe)
+ fprintf(f, "sae_pwe=%d\n", config->sae_pwe);
+
+ if (config->sae_pmkid_in_assoc)
+ fprintf(f, "sae_pmkid_in_assoc=%d\n",
+ config->sae_pmkid_in_assoc);
+
if (config->ap_vendor_elements) {
int i, len = wpabuf_len(config->ap_vendor_elements);
const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
@@ -1414,9 +1377,23 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->initial_freq_list && config->initial_freq_list[0]) {
+ int i;
+ fprintf(f, "initial_freq_list=");
+ for (i = 0; config->initial_freq_list[i]; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->initial_freq_list[i]);
+ }
+ fprintf(f, "\n");
+ }
if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+ if (config->scan_res_valid_for_connect !=
+ DEFAULT_SCAN_RES_VALID_FOR_CONNECT)
+ fprintf(f, "scan_res_valid_for_connect=%d\n",
+ config->scan_res_valid_for_connect);
+
if (config->sched_scan_interval)
fprintf(f, "sched_scan_interval=%u\n",
config->sched_scan_interval);
@@ -1547,6 +1524,12 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
config->p2p_interface_random_mac_addr);
if (config->disable_btm)
fprintf(f, "disable_btm=1\n");
+ if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
+ fprintf(f, "extended_key_id=%d\n",
+ config->extended_key_id);
+ if (config->wowlan_disconnect_on_deinit)
+ fprintf(f, "wowlan_disconnect_on_deinit=%d\n",
+ config->wowlan_disconnect_on_deinit);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1563,9 +1546,16 @@ int wpa_config_write(const char *name, struct wpa_config *config)
#endif /* CONFIG_NO_CONFIG_BLOBS */
int ret = 0;
const char *orig_name = name;
- int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
- char *tmp_name = os_malloc(tmp_len);
+ int tmp_len;
+ char *tmp_name;
+ if (!name) {
+ wpa_printf(MSG_ERROR, "No configuration file for writing");
+ return -1;
+ }
+
+ tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+ tmp_name = os_malloc(tmp_len);
if (tmp_name) {
os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
name = tmp_name;
@@ -1593,8 +1583,11 @@ int wpa_config_write(const char *name, struct wpa_config *config)
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
continue; /* do not save temporary networks */
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
- !ssid->passphrase)
+ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) &&
+ !ssid->psk_set && !ssid->passphrase)
+ continue; /* do not save invalid network */
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !ssid->passphrase && !ssid->sae_password)
continue; /* do not save invalid network */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
diff --git a/contrib/wpa/wpa_supplicant/config_ssid.h b/contrib/wpa/wpa_supplicant/config_ssid.h
index d5c5c00a9dfb..3f7b31480765 100644
--- a/contrib/wpa/wpa_supplicant/config_ssid.h
+++ b/contrib/wpa/wpa_supplicant/config_ssid.h
@@ -19,8 +19,13 @@
EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#ifdef CONFIG_NO_TKIP
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP)
+#else /* CONFIG_NO_TKIP */
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#endif /* CONFIG_NO_TKIP */
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
@@ -57,6 +62,12 @@ enum wpas_mode {
WPAS_MODE_MESH = 5,
};
+enum sae_pk_mode {
+ SAE_PK_MODE_AUTOMATIC = 0,
+ SAE_PK_MODE_ONLY = 1,
+ SAE_PK_MODE_DISABLED = 2,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -142,16 +153,16 @@ struct wpa_ssid {
u8 bssid[ETH_ALEN];
/**
- * bssid_blacklist - List of inacceptable BSSIDs
+ * bssid_ignore - List of inacceptable BSSIDs
*/
- u8 *bssid_blacklist;
- size_t num_bssid_blacklist;
+ u8 *bssid_ignore;
+ size_t num_bssid_ignore;
/**
- * bssid_blacklist - List of acceptable BSSIDs
+ * bssid_accept - List of acceptable BSSIDs
*/
- u8 *bssid_whitelist;
- size_t num_bssid_whitelist;
+ u8 *bssid_accept;
+ size_t num_bssid_accept;
/**
* bssid_set - Whether BSSID is configured for this network
@@ -213,6 +224,8 @@ struct wpa_ssid {
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -298,6 +311,7 @@ struct wpa_ssid {
struct eap_peer_config eap;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
/**
@@ -314,6 +328,7 @@ struct wpa_ssid {
* wep_tx_keyidx - Default key index for TX frames using WEP
*/
int wep_tx_keyidx;
+#endif /* CONFIG_WEP */
/**
* proactive_key_caching - Enable proactive key caching
@@ -446,7 +461,6 @@ struct wpa_ssid {
*/
char *id_str;
-#ifdef CONFIG_IEEE80211W
/**
* ieee80211w - Whether management frame protection is enabled
*
@@ -460,7 +474,6 @@ struct wpa_ssid {
* followed).
*/
enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
/**
@@ -486,6 +499,23 @@ struct wpa_ssid {
int frequency;
/**
+ * enable_edmg - Enable EDMG feature in STA/AP mode
+ *
+ * This flag is used for enabling the EDMG capability in STA/AP mode.
+ */
+ int enable_edmg;
+
+ /**
+ * edmg_channel - EDMG channel number
+ *
+ * This value is used to configure the EDMG channel bonding feature.
+ * In AP mode it defines the EDMG channel to start the AP on.
+ * in STA mode it defines the EDMG channel to use for connection
+ * (if supported by AP).
+ */
+ u8 edmg_channel;
+
+ /**
* fixed_freq - Use fixed frequency for IBSS
*/
int fixed_freq;
@@ -536,6 +566,19 @@ struct wpa_ssid {
*/
int wpa_ptk_rekey;
+ /** wpa_deny_ptk0_rekey - Control PTK0 rekeying
+ *
+ * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many
+ * broken implementations and should be avoided when using or
+ * interacting with one.
+ *
+ * 0 = always rekey when configured/instructed
+ * 1 = only rekey when the local driver is explicitly indicating it can
+ * perform this operation without issues
+ * 2 = never allow PTK0 rekeys
+ */
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
+
/**
* group_rekey - Group rekeying time in seconds
*
@@ -747,6 +790,16 @@ struct wpa_ssid {
vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE (IEEE 802.11ax) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* ap_max_inactivity - Timeout in seconds to detect STA's inactivity
*
@@ -971,6 +1024,32 @@ struct wpa_ssid {
size_t dpp_csign_len;
/**
+ * dpp_pp_key - ppKey (Configurator privacy protection public key)
+ */
+ u8 *dpp_pp_key;
+
+ /**
+ * dpp_pp_key_len - ppKey length in octets
+ */
+ size_t dpp_pp_key_len;
+
+ /**
+ * dpp_pfs - DPP PFS
+ * 0: allow PFS to be used or not used
+ * 1: require PFS to be used (note: not compatible with DPP R1)
+ * 2: do not allow PFS to be used
+ */
+ int dpp_pfs;
+
+ /**
+ * dpp_pfs_fallback - DPP PFS fallback selection
+ *
+ * This is an internally used variable (i.e., not used in external
+ * configuration) to track state of the DPP PFS fallback mechanism.
+ */
+ int dpp_pfs_fallback;
+
+ /**
* owe_group - OWE DH Group
*
* 0 = use default (19) first and then try all supported groups one by
@@ -992,6 +1071,19 @@ struct wpa_ssid {
int owe_only;
/**
+ * owe_ptk_workaround - OWE PTK derivation workaround
+ *
+ * Initial OWE implementation used SHA256 when deriving the PTK for all
+ * OWE groups. This was supposed to change to SHA384 for group 20 and
+ * SHA512 for group 21. This parameter can be used to enable older
+ * behavior mainly for testing purposes. There is no impact to group 19
+ * behavior, but if enabled, this will make group 20 and 21 cases use
+ * SHA256-based PTK derivation which will not work with the updated
+ * OWE implementation on the AP side.
+ */
+ int owe_ptk_workaround;
+
+ /**
* owe_transition_bss_select_count - OWE transition BSS select count
*
* This is an internally used variable (i.e., not used in external
@@ -1017,6 +1109,53 @@ struct wpa_ssid {
* FT initial mobility domain association.
*/
int ft_eap_pmksa_caching;
+
+ /**
+ * beacon_prot - Whether Beacon protection is enabled
+ *
+ * This depends on management frame protection (ieee80211w) being
+ * enabled.
+ */
+ int beacon_prot;
+
+ /**
+ * transition_disable - Transition Disable indication
+ * The AP can notify authenticated stations to disable transition mode
+ * in their network profiles when the network has completed transition
+ * steps, i.e., once sufficiently large number of APs in the ESS have
+ * been updated to support the more secure alternative. When this
+ * indication is used, the stations are expected to automatically
+ * disable transition mode and less secure security options. This
+ * includes use of WEP, TKIP (including use of TKIP as the group
+ * cipher), and connections without PMF.
+ * Bitmap bits:
+ * bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+ * and only allow SAE to be used)
+ * bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+ * bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+ * bit 3 (0x08): Enhanced Open (disable use of open network; require
+ * OWE)
+ */
+ u8 transition_disable;
+
+ /**
+ * sae_pk - SAE-PK mode
+ * 0 = automatic SAE/SAE-PK selection based on password; enable
+ * transition mode (allow SAE authentication without SAE-PK)
+ * 1 = SAE-PK only (disable transition mode; allow SAE authentication
+ * only with SAE-PK)
+ * 2 = disable SAE-PK (allow SAE authentication only without SAE-PK)
+ */
+ enum sae_pk_mode sae_pk;
+
+ /**
+ * was_recently_reconfigured - Whether this SSID config has been changed
+ * recently
+ *
+ * This is an internally used variable, i.e., not used in external
+ * configuration.
+ */
+ bool was_recently_reconfigured;
};
#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa/wpa_supplicant/config_winreg.c b/contrib/wpa/wpa_supplicant/config_winreg.c
new file mode 100644
index 000000000000..1b7f96ed2fb1
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/config_winreg.c
@@ -0,0 +1,1061 @@
+/*
+ * WPA Supplicant / Configuration backend: Windows registry
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements a configuration backend for Windows registry. All the
+ * configuration information is stored in the registry and the format for
+ * network configuration fields is same as described in the sample
+ * configuration file, wpa_supplicant.conf.
+ *
+ * Configuration data is in
+ * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
+ * key. Each configuration profile has its own key under this. In terms of text
+ * files, each profile would map to a separate text file with possibly multiple
+ * networks. Under each profile, there is a networks key that lists all
+ * networks as a subkey. Each network has set of values in the same way as
+ * network block in the configuration file. In addition, blobs subkey has
+ * possible blobs as values.
+ *
+ * Example network configuration block:
+ * \verbatim
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+ ssid="example"
+ key_mgmt=WPA-PSK
+\endverbatim
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "uuid.h"
+#include "config.h"
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
+{
+ struct wpa_config_blob *blob;
+ int errors = 0;
+ HKEY bhk;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "blobs key");
+ return 0; /* assume no blobs */
+ }
+
+ for (i = 0; ; i++) {
+#define TNAMELEN 255
+ TCHAR name[TNAMELEN];
+ char data[4096];
+ DWORD namelen, datalen, type;
+
+ namelen = TNAMELEN;
+ datalen = sizeof(data);
+ ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= TNAMELEN)
+ namelen = TNAMELEN - 1;
+ name[namelen] = TEXT('\0');
+ wpa_unicode2ascii_inplace(name);
+
+ if (datalen >= sizeof(data))
+ datalen = sizeof(data) - 1;
+
+ wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
+ (int) i, name, (int) datalen);
+
+ blob = os_zalloc(sizeof(*blob));
+ if (blob == NULL) {
+ errors++;
+ break;
+ }
+ blob->name = os_strdup((char *) name);
+ blob->data = os_memdup(data, datalen);
+ if (blob->name == NULL || blob->data == NULL) {
+ wpa_config_free_blob(blob);
+ errors++;
+ break;
+ }
+ blob->len = datalen;
+
+ wpa_config_set_blob(config, blob);
+ }
+
+ RegCloseKey(bhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
+{
+ DWORD val, buflen;
+ LONG ret;
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
+ *_val = val;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
+{
+ DWORD buflen;
+ LONG ret;
+ TCHAR *val;
+
+ buflen = 0;
+ ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
+ if (ret != ERROR_SUCCESS)
+ return NULL;
+ val = os_malloc(buflen);
+ if (val == NULL)
+ return NULL;
+
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
+ if (ret != ERROR_SUCCESS) {
+ os_free(val);
+ return NULL;
+ }
+
+ wpa_unicode2ascii_inplace(val);
+ wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
+ return (char *) val;
+}
+
+
+#ifdef CONFIG_WPS
+static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
+{
+ char *str;
+ int ret = 0;
+
+ str = wpa_config_read_reg_string(hk, TEXT("uuid"));
+ if (str == NULL)
+ return 0;
+
+ if (uuid_str2bin(str, config->uuid))
+ ret = -1;
+
+ os_free(str);
+
+ return ret;
+}
+
+
+static int wpa_config_read_global_os_version(struct wpa_config *config,
+ HKEY hk)
+{
+ char *str;
+ int ret = 0;
+
+ str = wpa_config_read_reg_string(hk, TEXT("os_version"));
+ if (str == NULL)
+ return 0;
+
+ if (hexstr2bin(str, config->os_version, 4))
+ ret = -1;
+
+ os_free(str);
+
+ return ret;
+}
+#endif /* CONFIG_WPS */
+
+
+static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
+{
+ int errors = 0;
+ int val;
+
+ wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
+ wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
+ &config->fast_reauth);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ (int *) &config->dot11RSNAConfigPMKLifetime);
+ wpa_config_read_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ (int *)
+ &config->dot11RSNAConfigPMKReauthThreshold);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ (int *) &config->dot11RSNAConfigSATimeout);
+ wpa_config_read_reg_dword(hk, TEXT("update_config"),
+ &config->update_config);
+
+ if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
+ &config->eapol_version) == 0) {
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
+ config->eapol_version);
+ errors++;
+ }
+ }
+
+ config->ctrl_interface = wpa_config_read_reg_string(
+ hk, TEXT("ctrl_interface"));
+
+#ifdef CONFIG_WPS
+ if (wpa_config_read_global_uuid(config, hk))
+ errors++;
+ wpa_config_read_reg_dword(hk, TEXT("auto_uuid"), &config->auto_uuid);
+ config->device_name = wpa_config_read_reg_string(
+ hk, TEXT("device_name"));
+ config->manufacturer = wpa_config_read_reg_string(
+ hk, TEXT("manufacturer"));
+ config->model_name = wpa_config_read_reg_string(
+ hk, TEXT("model_name"));
+ config->serial_number = wpa_config_read_reg_string(
+ hk, TEXT("serial_number"));
+ {
+ char *t = wpa_config_read_reg_string(
+ hk, TEXT("device_type"));
+ if (t && wps_dev_type_str2bin(t, config->device_type))
+ errors++;
+ os_free(t);
+ }
+ config->config_methods = wpa_config_read_reg_string(
+ hk, TEXT("config_methods"));
+ if (wpa_config_read_global_os_version(config, hk))
+ errors++;
+ wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
+ &config->wps_cred_processing);
+ wpa_config_read_reg_dword(hk, TEXT("wps_cred_add_sae"),
+ &config->wps_cred_add_sae);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ config->p2p_ssid_postfix = wpa_config_read_reg_string(
+ hk, TEXT("p2p_ssid_postfix"));
+ wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
+ (int *) &config->p2p_group_idle);
+#endif /* CONFIG_P2P */
+
+ wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
+ (int *) &config->bss_max_count);
+ wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
+ &config->filter_ssids);
+ wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
+ (int *) &config->max_num_sta);
+ wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
+ (int *) &config->disassoc_low_ack);
+
+ wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+ wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+ config->pmf = val;
+ if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
+ &val) == 0) {
+ if (val < 0 || val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Invalid Extended Key ID setting (%d)", val);
+ errors++;
+ }
+ config->extended_key_id = val;
+ }
+
+ return errors ? -1 : 0;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
+ int id)
+{
+ HKEY nhk;
+ LONG ret;
+ DWORD i;
+ struct wpa_ssid *ssid;
+ int errors = 0;
+
+ ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "network '" TSTR "'", netw);
+ return NULL;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
+ ssid = os_zalloc(sizeof(*ssid));
+ if (ssid == NULL) {
+ RegCloseKey(nhk);
+ return NULL;
+ }
+ dl_list_init(&ssid->psk_list);
+ ssid->id = id;
+
+ wpa_config_set_network_defaults(ssid);
+
+ for (i = 0; ; i++) {
+ TCHAR name[255], data[1024];
+ DWORD namelen, datalen, type;
+
+ namelen = 255;
+ datalen = sizeof(data);
+ ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ if (datalen >= 1024)
+ datalen = 1024 - 1;
+ data[datalen] = TEXT('\0');
+
+ wpa_unicode2ascii_inplace(name);
+ wpa_unicode2ascii_inplace(data);
+ if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
+ errors++;
+ }
+
+ RegCloseKey(nhk);
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Both PSK and passphrase "
+ "configured for network '" TSTR "'.", netw);
+ errors++;
+ }
+ wpa_config_update_psk(ssid);
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
+ "list since it was not allowed for pairwise "
+ "cipher for network '" TSTR "'.", netw);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ if (errors) {
+ wpa_config_free_ssid(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
+{
+ HKEY nhk;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ int errors = 0;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
+ &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
+ "registry key");
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+ ssid = wpa_config_read_network(nhk, name, i);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to parse network "
+ "profile '%s'.", name);
+ errors++;
+ continue;
+ }
+ if (head == NULL) {
+ head = tail = ssid;
+ } else {
+ tail->next = ssid;
+ tail = ssid;
+ }
+ if (wpa_config_add_prio_network(config, ssid)) {
+ wpa_printf(MSG_ERROR, "Failed to add network profile "
+ "'%s' to priority list.", name);
+ errors++;
+ continue;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ config->ssid = head;
+
+ return errors ? -1 : 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
+{
+ TCHAR buf[256];
+ int errors = 0;
+ struct wpa_config *config;
+ HKEY hk;
+ LONG ret;
+
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry HKLM\\" TSTR, buf);
+ os_free(config);
+ return NULL;
+ }
+
+ if (wpa_config_read_global(config, hk))
+ errors++;
+
+ if (wpa_config_read_networks(config, hk))
+ errors++;
+
+ if (wpa_config_read_blobs(config, hk))
+ errors++;
+
+ wpa_config_debug_dump_networks(config);
+
+ RegCloseKey(hk);
+
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ }
+
+ return config;
+}
+
+
+static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
+ int def)
+{
+ LONG ret;
+ DWORD _val = val;
+
+ if (val == def) {
+ RegDeleteValue(hk, name);
+ return 0;
+ }
+
+ ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
+ sizeof(_val));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
+ name, val, (int) GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_write_reg_string(HKEY hk, const char *name,
+ const char *val)
+{
+ LONG ret;
+ TCHAR *_name, *_val;
+
+ _name = wpa_strdup_tchar(name);
+ if (_name == NULL)
+ return -1;
+
+ if (val == NULL) {
+ RegDeleteValue(hk, _name);
+ os_free(_name);
+ return 0;
+ }
+
+ _val = wpa_strdup_tchar(val);
+ if (_val == NULL) {
+ os_free(_name);
+ return -1;
+ }
+ ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
+ (os_strlen(val) + 1) * sizeof(TCHAR));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
+ "error %d", name, val, (int) GetLastError());
+ os_free(_name);
+ os_free(_val);
+ return -1;
+ }
+
+ os_free(_name);
+ os_free(_val);
+ return 0;
+}
+
+
+static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
+{
+#ifdef CONFIG_CTRL_IFACE
+ wpa_config_write_reg_string(hk, "ctrl_interface",
+ config->ctrl_interface);
+#endif /* CONFIG_CTRL_IFACE */
+
+ wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
+ config->eapol_version,
+ DEFAULT_EAPOL_VERSION);
+ wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
+ DEFAULT_AP_SCAN);
+ wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
+ config->fast_reauth, DEFAULT_FAST_REAUTH);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ config->dot11RSNAConfigPMKLifetime, 0);
+ wpa_config_write_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ config->dot11RSNAConfigPMKReauthThreshold,
+ 0);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ config->dot11RSNAConfigSATimeout, 0);
+ wpa_config_write_reg_dword(hk, TEXT("update_config"),
+ config->update_config,
+ 0);
+#ifdef CONFIG_WPS
+ if (!is_nil_uuid(config->uuid)) {
+ char buf[40];
+ uuid_bin2str(config->uuid, buf, sizeof(buf));
+ wpa_config_write_reg_string(hk, "uuid", buf);
+ }
+ wpa_config_write_reg_dword(hk, TEXT("auto_uuid"), config->auto_uuid,
+ 0);
+ wpa_config_write_reg_string(hk, "device_name", config->device_name);
+ wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
+ wpa_config_write_reg_string(hk, "model_name", config->model_name);
+ wpa_config_write_reg_string(hk, "model_number", config->model_number);
+ wpa_config_write_reg_string(hk, "serial_number",
+ config->serial_number);
+ {
+ char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+ buf = wps_dev_type_bin2str(config->device_type,
+ _buf, sizeof(_buf));
+ wpa_config_write_reg_string(hk, "device_type", buf);
+ }
+ wpa_config_write_reg_string(hk, "config_methods",
+ config->config_methods);
+ if (WPA_GET_BE32(config->os_version)) {
+ char vbuf[10];
+ os_snprintf(vbuf, sizeof(vbuf), "%08x",
+ WPA_GET_BE32(config->os_version));
+ wpa_config_write_reg_string(hk, "os_version", vbuf);
+ }
+ wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
+ config->wps_cred_processing, 0);
+ wpa_config_write_reg_dword(hk, TEXT("wps_cred_add_sae"),
+ config->wps_cred_add_sae, 0);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
+ config->p2p_ssid_postfix);
+ wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
+ config->p2p_group_idle, 0);
+#endif /* CONFIG_P2P */
+
+ wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
+ config->bss_max_count,
+ DEFAULT_BSS_MAX_COUNT);
+ wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
+ config->filter_ssids, 0);
+ wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
+ config->max_num_sta, DEFAULT_MAX_NUM_STA);
+ wpa_config_write_reg_dword(hk, TEXT("ap_isolate"),
+ config->ap_isolate, DEFAULT_AP_ISOLATE);
+ wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
+ config->disassoc_low_ack, 0);
+
+ wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+ wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
+ wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+ config->external_sim, 0);
+
+ return 0;
+}
+
+
+static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
+{
+ HKEY nhk;
+ int i, errors = 0;
+ LONG ret;
+
+ ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
+ "' for subkey deletion: error 0x%x (%d)", key,
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ ret = RegDeleteKey(nhk, name);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ errors++;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, field);
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+}
+
+
+static void write_int(HKEY hk, const char *field, int value, int def)
+{
+ char val[20];
+ if (value == def)
+ return;
+ os_snprintf(val, sizeof(val), "%d", value);
+ wpa_config_write_reg_string(hk, field, val);
+}
+
+
+static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "bssid");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "bssid", value);
+ os_free(value);
+}
+
+
+static void write_psk(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "psk");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "psk", value);
+ os_free(value);
+}
+
+
+static void write_proto(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->proto == DEFAULT_PROTO)
+ return;
+
+ value = wpa_config_get(ssid, "proto");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "proto", value);
+ os_free(value);
+}
+
+
+static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ return;
+
+ value = wpa_config_get(ssid, "key_mgmt");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "key_mgmt", value);
+ os_free(value);
+}
+
+
+static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
+ return;
+
+ value = wpa_config_get(ssid, "pairwise");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "pairwise", value);
+ os_free(value);
+}
+
+
+static void write_group(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->group_cipher == DEFAULT_GROUP)
+ return;
+
+ value = wpa_config_get(ssid, "group");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "group", value);
+ os_free(value);
+}
+
+
+static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->auth_alg == 0)
+ return;
+
+ value = wpa_config_get(ssid, "auth_alg");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "auth_alg", value);
+ os_free(value);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void write_eap(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ value = wpa_config_get(ssid, "eap");
+ if (value == NULL)
+ return;
+
+ if (value[0])
+ wpa_config_write_reg_string(hk, "eap", value);
+ os_free(value);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifdef CONFIG_WEP
+static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
+{
+ char field[20], *value;
+
+ os_snprintf(field, sizeof(field), "wep_key%d", idx);
+ value = wpa_config_get(ssid, field);
+ if (value) {
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+ }
+}
+#endif /* CONFIG_WEP */
+
+
+static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
+{
+ int errors = 0;
+ HKEY nhk, netw;
+ LONG ret;
+ TCHAR name[5];
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
+ "for subkey addition: error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+#ifdef UNICODE
+ wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+ os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+ ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
+ NULL);
+ RegCloseKey(nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
+ " error 0x%x (%d)",
+ name, (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+#define STR(t) write_str(netw, #t, ssid)
+#define INT(t) write_int(netw, #t, ssid->t, 0)
+#define INTe(t, m) write_int(netw, #t, ssid->eap.m, 0)
+#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
+#define INT_DEFe(t, m, def) write_int(netw, #t, ssid->eap.m, def)
+
+ STR(ssid);
+ INT(scan_ssid);
+ write_bssid(netw, ssid);
+ write_psk(netw, ssid);
+ STR(sae_password);
+ STR(sae_password_id);
+ write_proto(netw, ssid);
+ write_key_mgmt(netw, ssid);
+ write_pairwise(netw, ssid);
+ write_group(netw, ssid);
+ write_auth_alg(netw, ssid);
+#ifdef IEEE8021X_EAPOL
+ write_eap(netw, ssid);
+ STR(identity);
+ STR(anonymous_identity);
+ STR(imsi_identity);
+ STR(password);
+ STR(ca_cert);
+ STR(ca_path);
+ STR(client_cert);
+ STR(private_key);
+ STR(private_key_passwd);
+ STR(dh_file);
+ STR(subject_match);
+ STR(check_cert_subject);
+ STR(altsubject_match);
+ STR(ca_cert2);
+ STR(ca_path2);
+ STR(client_cert2);
+ STR(private_key2);
+ STR(private_key2_passwd);
+ STR(dh_file2);
+ STR(subject_match2);
+ STR(check_cert_subject2);
+ STR(altsubject_match2);
+ STR(phase1);
+ STR(phase2);
+ STR(pcsc);
+ STR(pin);
+ STR(engine_id);
+ STR(key_id);
+ STR(cert_id);
+ STR(ca_cert_id);
+ STR(key2_id);
+ STR(pin2);
+ STR(engine2_id);
+ STR(cert2_id);
+ STR(ca_cert2_id);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
+ INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(netw, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
+ INT(priority);
+#ifdef IEEE8021X_EAPOL
+ INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+ STR(pac_file);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
+ INT(mode);
+ write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+ -1);
+ INT(disabled);
+ write_int(netw, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
+ STR(id_str);
+#ifdef CONFIG_HS20
+ INT(update_identifier);
+#endif /* CONFIG_HS20 */
+ INT(group_rekey);
+ INT(ft_eap_pmksa_caching);
+
+#undef STR
+#undef INT
+#undef INT_DEF
+
+ RegCloseKey(netw);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
+{
+ HKEY bhk;
+ LONG ret;
+ TCHAR *name;
+
+ ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
+ &bhk, NULL);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
+ "error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+ name = wpa_strdup_tchar(blob->name);
+ ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
+ blob->len);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
+ "error 0x%x (%d)", blob->name, (unsigned int) ret,
+ (int) GetLastError());
+ RegCloseKey(bhk);
+ os_free(name);
+ return -1;
+ }
+ os_free(name);
+
+ RegCloseKey(bhk);
+
+ return 0;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+ TCHAR buf[256];
+ HKEY hk;
+ LONG ret;
+ int errors = 0;
+ struct wpa_ssid *ssid;
+ struct wpa_config_blob *blob;
+ int id;
+
+ wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry %s: error %d", buf,
+ (int) GetLastError());
+ return -1;
+ }
+
+ if (wpa_config_write_global(config, hk)) {
+ wpa_printf(MSG_ERROR, "Failed to write global configuration "
+ "data");
+ errors++;
+ }
+
+ wpa_config_delete_subkeys(hk, TEXT("networks"));
+ for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ continue; /* do not save temporary WPS networks */
+ if (wpa_config_write_network(hk, ssid, id))
+ errors++;
+ }
+
+ RegDeleteKey(hk, TEXT("blobs"));
+ for (blob = config->blobs; blob; blob = blob->next) {
+ if (wpa_config_write_blob(hk, blob))
+ errors++;
+ }
+
+ RegCloseKey(hk);
+
+ wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
+ name, errors ? "un" : "");
+ return errors ? -1 : 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.c b/contrib/wpa/wpa_supplicant/ctrl_iface.c
index 8efc08d4d906..8a6a829b6665 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,7 +11,6 @@
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
-#include <net/ethernet.h>
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
@@ -23,6 +22,7 @@
#ifdef CONFIG_DPP
#include "common/dpp.h"
#endif /* CONFIG_DPP */
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "ap/hostapd.h"
#include "eap_peer/eap.h"
@@ -39,6 +39,7 @@
#include "driver_i.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
+#include "wpas_glue.h"
#include "ap.h"
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
@@ -49,7 +50,7 @@
#include "scan.h"
#include "ctrl_iface.h"
#include "interworking.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "autoscan.h"
#include "wnm_sta.h"
#include "offchannel.h"
@@ -58,6 +59,12 @@
#include "dpp_supplicant.h"
#include "sme.h"
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS)
+#include <net/ethernet.h>
+#endif
+
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@@ -294,20 +301,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
}
-static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
+static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *bands)
{
union wpa_event_data event;
+ u32 setband_mask = WPA_SETBAND_AUTO;
- if (os_strcmp(band, "AUTO") == 0)
- wpa_s->setband = WPA_SETBAND_AUTO;
- else if (os_strcmp(band, "5G") == 0)
- wpa_s->setband = WPA_SETBAND_5G;
- else if (os_strcmp(band, "2G") == 0)
- wpa_s->setband = WPA_SETBAND_2G;
- else
- return -1;
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
- if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
+ wpa_s->setband_mask = setband_mask;
+ if (wpa_drv_setband(wpa_s, wpa_s->setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@@ -414,6 +431,64 @@ static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_TESTING_OPTIONS
+static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s,
+ const char *val)
+{
+ u8 bssid[ETH_ALEN];
+ const char *pos = val;
+ struct driver_signal_override *dso = NULL, *tmp, parsed;
+
+ if (hwaddr_aton(pos, bssid))
+ return -1;
+ pos = os_strchr(pos, ' ');
+
+ dl_list_for_each(tmp, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+ dso = tmp;
+ break;
+ }
+ }
+
+ if (!pos) {
+ /* Remove existing entry */
+ if (dso) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+ return 0;
+ }
+ pos++;
+
+ /* Update an existing entry or add a new one */
+ os_memset(&parsed, 0, sizeof(parsed));
+ if (sscanf(pos, "%d %d %d %d %d",
+ &parsed.si_current_signal,
+ &parsed.si_avg_signal,
+ &parsed.si_avg_beacon_signal,
+ &parsed.si_current_noise,
+ &parsed.scan_level) != 5)
+ return -1;
+
+ if (!dso) {
+ dso = os_zalloc(sizeof(*dso));
+ if (!dso)
+ return -1;
+ os_memcpy(dso->bssid, bssid, ETH_ALEN);
+ dl_list_add(&wpa_s->drv_signal_override, &dso->list);
+ }
+ dso->si_current_signal = parsed.si_current_signal;
+ dso->si_avg_signal = parsed.si_avg_signal;
+ dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal;
+ dso->si_current_noise = parsed.si_current_noise;
+ dso->scan_level = parsed.scan_level;
+
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -438,6 +513,19 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
eapol_sm_configure(wpa_s->eapol,
-1, -1, -1, atoi(value));
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "EAPOL::portControl") == 0) {
+ if (os_strcmp(value, "Auto") == 0)
+ eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+ else if (os_strcmp(value, "ForceUnauthorized") == 0)
+ eapol_sm_notify_portControl(wpa_s->eapol,
+ ForceUnauthorized);
+ else if (os_strcmp(value, "ForceAuthorized") == 0)
+ eapol_sm_notify_portControl(wpa_s->eapol,
+ ForceAuthorized);
+ else
+ ret = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
atoi(value))) {
@@ -633,6 +721,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = -1;
else
dpp_nonce_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
+ dpp_version_override = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
#ifdef CONFIG_TESTING_OPTIONS
@@ -658,6 +748,72 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->ignore_assoc_disallow = !!atoi(value);
wpa_drv_ignore_assoc_disallow(wpa_s,
wpa_s->ignore_assoc_disallow);
+ } else if (os_strcasecmp(cmd, "disable_sa_query") == 0) {
+ wpa_s->disable_sa_query = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) {
+ wpa_s->ignore_sae_h2e_only = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) {
+ char *pos;
+
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ pos = value;
+ while (pos && pos[0]) {
+ int group;
+
+ group = atoi(pos);
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Extra rejection of SAE group %d",
+ group);
+ if (group)
+ int_array_add_unique(
+ &wpa_s->extra_sae_rejected_groups,
+ group);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ break;
+ pos++;
+ }
+ } else if (os_strcasecmp(cmd, "ft_rsnxe_used") == 0) {
+ wpa_s->ft_rsnxe_used = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol") == 0) {
+ wpa_s->oci_freq_override_eapol = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_saquery_req") == 0) {
+ wpa_s->oci_freq_override_saquery_req = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_saquery_resp") == 0) {
+ wpa_s->oci_freq_override_saquery_resp = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol_g2") == 0) {
+ wpa_s->oci_freq_override_eapol_g2 = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_ft_assoc") == 0) {
+ wpa_s->oci_freq_override_ft_assoc = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_fils_assoc") == 0) {
+ wpa_s->oci_freq_override_fils_assoc = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_wnm_sleep") == 0) {
+ wpa_s->oci_freq_override_wnm_sleep = atoi(value);
+ } else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsne_override_eapol = NULL;
+ else
+ wpa_s->rsne_override_eapol = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsnxe_override_assoc = NULL;
+ else
+ wpa_s->rsnxe_override_assoc = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "rsnxe_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsnxe_override_eapol = NULL;
+ else
+ wpa_s->rsnxe_override_eapol = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
wpa_s->reject_btm_req_reason = atoi(value);
} else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
@@ -672,6 +828,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->sae_commit_override = NULL;
else
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
+ ret = wpas_ctrl_iface_set_dso(wpa_s, value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -765,6 +923,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
if (ret == 0)
wpa_supplicant_update_config(wpa_s);
+ else if (ret == 1)
+ ret = 0;
}
return ret;
@@ -780,6 +940,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
if (os_strcmp(cmd, "version") == 0) {
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+ } else if (os_strcasecmp(cmd, "max_command_len") == 0) {
+ res = os_snprintf(buf, buflen, "%u", CTRL_IFACE_MAX_LEN);
} else if (os_strcasecmp(cmd, "country") == 0) {
if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
res = os_snprintf(buf, buflen, "%c%c",
@@ -810,6 +972,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
return wpa_snprintf_hex(buf, buflen,
wpa_sm_get_anonce(wpa_s->wpa),
WPA_NONCE_LEN);
+ } else if (os_strcasecmp(cmd, "last_tk_key_idx") == 0) {
+ res = os_snprintf(buf, buflen, "%d", wpa_s->last_tk_key_idx);
#endif /* CONFIG_TESTING_OPTIONS */
} else {
res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
@@ -2160,8 +2324,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
wpa_s->sme.sae.state == SAE_ACCEPTED) {
- ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
- wpa_s->sme.sae.group);
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n"
+ "sae_h2e=%d\n"
+ "sae_pk=%d\n",
+ wpa_s->sme.sae.group,
+ wpa_s->sme.sae.h2e,
+ wpa_s->sme.sae.pk);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2400,20 +2568,20 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
- char *cmd, char *buf,
- size_t buflen)
+static int wpa_supplicant_ctrl_iface_bssid_ignore(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
{
u8 bssid[ETH_ALEN];
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
char *pos, *end;
int ret;
- /* cmd: "BLACKLIST [<BSSID>]" */
+ /* cmd: "BSSID_IGNORE [<BSSID>]" */
if (*cmd == '\0') {
pos = buf;
end = buf + buflen;
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
while (e) {
ret = os_snprintf(pos, end - pos, MACSTR "\n",
MAC2STR(e->bssid));
@@ -2427,12 +2595,12 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
cmd++;
if (os_strncmp(cmd, "clear", 5) == 0) {
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
os_memcpy(buf, "OK\n", 3);
return 3;
}
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: BSSID_IGNORE bssid='%s'", cmd);
if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
return -1;
@@ -2442,10 +2610,10 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
* Add the BSSID twice, so its count will be 2, causing it to be
* skipped when processing scan results.
*/
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
os_memcpy(buf, "OK\n", 3);
@@ -2654,7 +2822,6 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
pos += ret;
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
pos == start ? "" : "+");
@@ -2669,7 +2836,6 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
return pos;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SUITEB
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
@@ -2819,7 +2985,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe, *rsnxe;
mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2846,6 +3012,19 @@ static int wpa_supplicant_ctrl_iface_scan_result(
pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
ie2, 2 + ie2[1]);
}
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -2873,6 +3052,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
}
if (bss_is_dmg(bss)) {
const char *s;
+
+ if (wpa_bss_get_ie_ext(bss, WLAN_EID_EXT_EDMG_OPERATION)) {
+ ret = os_snprintf(pos, end - pos, "[EDMG]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
ret = os_snprintf(pos, end - pos, "[DMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -3315,38 +3502,12 @@ static int wpa_supplicant_ctrl_iface_remove_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
int id;
- struct wpa_ssid *ssid;
int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- if (wpa_s->current_ssid) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(
- wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- }
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- if (wpa_s->last_ssid == remove_ssid)
- wpa_s->last_ssid = NULL;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
- return 0;
+ return wpa_supplicant_remove_all_networks(wpa_s);
}
id = atoi(cmd);
@@ -3382,6 +3543,20 @@ static int wpa_supplicant_ctrl_iface_update_network(
if (ret == 1)
return 0; /* No change to the previously configured value */
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(name, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network and
+ * return. There's no need to flush caches for bgscan parameter
+ * changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ return 0;
+ }
+#endif /* CONFIG_BGSCAN */
+
if (os_strcmp(name, "bssid") != 0 &&
os_strcmp(name, "bssid_hint") != 0 &&
os_strcmp(name, "priority") != 0) {
@@ -3839,10 +4014,14 @@ static const struct cipher_info ciphers[] = {
{ WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
{ WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+#ifndef CONFIG_NO_TKIP
{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+#endif /* CONFIG_NO_TKIP */
{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+#ifdef CONFIG_WEP
{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+#endif /* CONFIG_WEP */
};
static const struct cipher_info ciphers_group_mgmt[] = {
@@ -3853,7 +4032,7 @@ static const struct cipher_info ciphers_group_mgmt[] = {
};
-static int ctrl_iface_get_capability_pairwise(int res, char *strict,
+static int ctrl_iface_get_capability_pairwise(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3868,7 +4047,11 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP NONE", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
+#endif /* CONFIG_NO_TKIP */
if (len >= buflen)
return -1;
return len;
@@ -3889,7 +4072,7 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
}
-static int ctrl_iface_get_capability_group(int res, char *strict,
+static int ctrl_iface_get_capability_group(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3904,7 +4087,19 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_WEP
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP WEP104 WEP40", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+#endif /* CONFIG_NO_TKIP */
+#else /* CONFIG_WEP */
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP", buflen);
+#else /* CONFIG_NO_TKIP */
+ len = os_strlcpy(buf, "CCMP TKIP", buflen);
+#endif /* CONFIG_NO_TKIP */
+#endif /* CONFIG_WEP */
if (len >= buflen)
return -1;
return len;
@@ -3925,7 +4120,7 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
}
-static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+static int ctrl_iface_get_capability_group_mgmt(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3954,11 +4149,49 @@ static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
}
-static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
+static int iftype_str_to_index(const char *iftype_str)
+{
+ if (!iftype_str)
+ return WPA_IF_MAX;
+
+ if (os_strcmp(iftype_str, "STATION") == 0)
+ return WPA_IF_STATION;
+
+ if (os_strcmp(iftype_str, "AP_VLAN") == 0)
+ return WPA_IF_AP_VLAN;
+
+ if (os_strcmp(iftype_str, "AP") == 0)
+ return WPA_IF_AP_BSS;
+
+ if (os_strcmp(iftype_str, "P2P_GO") == 0)
+ return WPA_IF_P2P_GO;
+
+ if (os_strcmp(iftype_str, "P2P_CLIENT") == 0)
+ return WPA_IF_P2P_CLIENT;
+
+ if (os_strcmp(iftype_str, "P2P_DEVICE") == 0)
+ return WPA_IF_P2P_DEVICE;
+
+ if (os_strcmp(iftype_str, "MESH") == 0)
+ return WPA_IF_MESH;
+
+ if (os_strcmp(iftype_str, "IBSS") == 0)
+ return WPA_IF_IBSS;
+
+ if (os_strcmp(iftype_str, "NAN") == 0)
+ return WPA_IF_NAN;
+
+ return WPA_IF_MAX;
+}
+
+
+static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
struct wpa_driver_capa *capa,
+ const char *iftype_str,
char *buf, size_t buflen)
{
int ret;
+ unsigned int key_mgmt;
char *pos, *end;
size_t len;
@@ -3975,36 +4208,68 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
return len;
}
+ if (iftype_str) {
+ enum wpa_driver_if_type iftype;
+
+ iftype = iftype_str_to_index(iftype_str);
+ if (iftype == WPA_IF_MAX)
+ return -1;
+ key_mgmt = capa->key_mgmt_iftype[iftype];
+ } else {
+ key_mgmt = capa->key_mgmt;
+ }
+
ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+ if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
ret = os_snprintf(pos, end - pos, " WPA-EAP");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ if (key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ret = os_snprintf(pos, end - pos, " WPA-PSK");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, " WPA-NONE");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK) {
+ ret = os_snprintf(pos, end - pos, " WAPI-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE) {
+ ret = os_snprintf(pos, end - pos, " TPK-HANDSHAKE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_CCKM) {
+ ret = os_snprintf(pos, end - pos, " CCKM");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_SUITEB
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4012,7 +4277,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_SUITEB */
#ifdef CONFIG_SUITEB192
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4020,7 +4285,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_SUITEB192 */
#ifdef CONFIG_OWE
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
ret = os_snprintf(pos, end - pos, " OWE");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4028,7 +4293,7 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
ret = os_snprintf(pos, end - pos, " DPP");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4036,26 +4301,26 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
#endif /* CONFIG_DPP */
#ifdef CONFIG_FILS
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
ret = os_snprintf(pos, end - pos, " FILS-SHA256");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
ret = os_snprintf(pos, end - pos, " FILS-SHA384");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#ifdef CONFIG_IEEE80211R
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
@@ -4064,27 +4329,72 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+ if (key_mgmt & WPA_DRIVER_CAPA_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 (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_SAE
+ if (key_mgmt & WPA_DRIVER_CAPA_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 */
+#ifdef CONFIG_SHA384
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+ if (key_mgmt & WPA_DRIVER_CAPA_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 */
+#ifdef CONFIG_SHA256
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_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;
+ }
+#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_HS20
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, " OSEN");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
return pos - buf;
}
-static int ctrl_iface_get_capability_proto(int res, char *strict,
+static int ctrl_iface_get_capability_proto(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4127,7 +4437,7 @@ static int ctrl_iface_get_capability_proto(int res, char *strict,
static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
- int res, char *strict,
+ int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4201,11 +4511,20 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FILS_SK_PFS */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ ret = os_snprintf(pos, end - pos, "%sPASN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+#endif /* CONFIG_PASN */
+
return pos - buf;
}
-static int ctrl_iface_get_capability_modes(int res, char *strict,
+static int ctrl_iface_get_capability_modes(int res, bool strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -4368,23 +4687,36 @@ static int wpa_supplicant_ctrl_iface_get_capability(
{
struct wpa_driver_capa capa;
int res;
- char *strict;
- char field[30];
+ char *next_param, *curr_param, *iftype = NULL;
+ bool strict = false;
+ char field[50];
size_t len;
/* Determine whether or not strict checking was requested */
len = os_strlcpy(field, _field, sizeof(field));
if (len >= sizeof(field))
return -1;
- strict = os_strchr(field, ' ');
- if (strict != NULL) {
- *strict++ = '\0';
- if (os_strcmp(strict, "strict") != 0)
+
+ next_param = os_strchr(field, ' ');
+ while (next_param) {
+ *next_param++ = '\0';
+ curr_param = next_param;
+ next_param = os_strchr(next_param, ' ');
+
+ if (next_param)
+ *next_param = '\0';
+
+ if (os_strcmp(curr_param, "strict") == 0)
+ strict = true;
+ else if (os_strncmp(curr_param, "iftype=", 7) == 0)
+ iftype = curr_param + 7;
+ else
return -1;
}
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
- field, strict ? strict : "");
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'%s%s%s",
+ field, iftype ? " iftype=" : "", iftype ? iftype : "",
+ strict ? " strict" : "");
if (os_strcmp(field, "eap") == 0) {
return eap_get_names(buf, buflen);
@@ -4406,7 +4738,7 @@ static int wpa_supplicant_ctrl_iface_get_capability(
if (os_strcmp(field, "key_mgmt") == 0)
return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
- buf, buflen);
+ iftype, buf, buflen);
if (os_strcmp(field, "proto") == 0)
return ctrl_iface_get_capability_proto(res, strict, &capa,
@@ -4499,6 +4831,45 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ if (os_strcmp(field, "sae") == 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+#ifdef CONFIG_SAE_PK
+ res = os_snprintf(buf, buflen, "H2E PK");
+#else /* CONFIG_SAE_PK */
+ res = os_snprintf(buf, buflen, "H2E");
+#endif /* CONFIG_SAE_PK */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_OCV
+ if (os_strcmp(field, "ocv") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_OCV */
+
+ if (os_strcmp(field, "beacon_prot") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION) ||
+ (wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4619,7 +4990,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *mesh, *owe, *rsnxe;
pos = buf;
end = buf + buflen;
@@ -4708,7 +5079,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
for (i = 0; i < bss->ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
if (os_snprintf_error(end - pos, ret))
@@ -4739,6 +5110,19 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = wpa_supplicant_ie_txt(pos, end,
mesh ? "RSN" : "WPA2", ie2,
2 + ie2[1]);
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -4860,7 +5244,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_WPS
if (mask & WPA_BSS_MASK_WPS_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -4871,7 +5255,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_P2P
if (mask & WPA_BSS_MASK_P2P_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -4883,7 +5267,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_WIFI_DISPLAY
if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
struct wpabuf *wfd;
- ie = (const u8 *) (bss + 1);
+
+ ie = wpa_bss_ie_ptr(bss);
wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
WFD_IE_VENDOR_TYPE);
if (wfd) {
@@ -4955,13 +5340,21 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_snprintf(title, sizeof(title), "anqp[%u]",
elem->infoid);
pos = anqp_add_hex(pos, end, title, elem->payload);
+ if (elem->protected_response) {
+ ret = os_snprintf(pos, end - pos,
+ "protected-anqp-info[%u]=1\n",
+ elem->infoid);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
}
}
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_MESH
if (mask & WPA_BSS_MASK_MESH_SCAN) {
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
if (ret >= end - pos)
return 0;
@@ -5008,7 +5401,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
- ie = (const u8 *) (bss + 1);
+ ie = wpa_bss_ie_ptr(bss);
ie += bss->ie_len;
for (i = 0; i < bss->beacon_ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
@@ -5237,17 +5630,24 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
/* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
- 0);
+ 0, KEY_FLAG_PAIRWISE);
+ if (wpa_sm_ext_key_id(wpa_s->wpa))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -5266,6 +5666,7 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
struct wpa_bss *bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_radio_work *already_connecting;
if (hwaddr_aton(addr, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
@@ -5293,9 +5694,18 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
* allow roaming to other networks
*/
+ already_connecting = radio_work_pending(wpa_s, "sme-connect");
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
+ /*
+ * Indicate that an explicitly requested roam is in progress so scan
+ * results that come in before the 'sme-connect' radio work gets
+ * executed do not override the original connection attempt.
+ */
+ if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
+ wpa_s->roam_in_progress = true;
+
return 0;
#endif /* CONFIG_NO_SCAN_PROCESSING */
}
@@ -5313,12 +5723,16 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
u8 seek_count = 0;
int freq = 0;
+ bool include_6ghz = false;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_INFO,
"Reject P2P_FIND since interface is disabled");
return -1;
}
+
+ if (os_strstr(cmd, " include_6ghz"))
+ include_6ghz = true;
if (os_strstr(cmd, "type=social"))
type = P2P_FIND_ONLY_SOCIAL;
else if (os_strstr(cmd, "type=progressive"))
@@ -5378,7 +5792,8 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
}
return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
- _dev_id, search_delay, seek_count, seek, freq);
+ _dev_id, search_delay, seek_count, seek, freq,
+ include_6ghz);
}
@@ -5627,9 +6042,11 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int freq = 0;
int pd;
int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
size_t group_ssid_len = 0;
int he;
+ bool allow_6ghz;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -5642,7 +6059,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -5667,6 +6084,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
}
}
join = os_strstr(pos, " join") != NULL;
+ allow_6ghz = os_strstr(pos, " allow_6ghz") != NULL;
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
@@ -5674,6 +6092,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -5744,8 +6163,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, freq2, persistent_id,
- pd, ht40, vht, max_oper_chwidth, he,
- group_ssid, group_ssid_len);
+ pd, ht40, vht, max_oper_chwidth, he, edmg,
+ group_ssid, group_ssid_len, allow_6ghz);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -6301,6 +6720,8 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
+ bool allow_6ghz;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -6338,6 +6759,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos = os_strstr(cmd, "freq2=");
if (pos)
@@ -6351,8 +6773,11 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
if (max_oper_chwidth < 0)
return -1;
+ allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL;
+
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
- max_oper_chwidth, pref_freq, he);
+ max_oper_chwidth, pref_freq, he, edmg,
+ allow_6ghz);
}
@@ -6360,6 +6785,7 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos;
u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
+ bool allow_6ghz;
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -6372,6 +6798,8 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
+ allow_6ghz = os_strstr(pos, " allow_6ghz") != NULL;
+
pos = os_strstr(pos, " go_dev_addr=");
if (pos) {
pos += 13;
@@ -6383,7 +6811,7 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
go_dev = go_dev_addr;
}
- return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
+ return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev, allow_6ghz);
}
@@ -6401,7 +6829,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
int id, int freq, int vht_center_freq2,
int ht40, int vht, int vht_chwidth,
- int he)
+ int he, int edmg, bool allow_6ghz)
{
struct wpa_ssid *ssid;
@@ -6415,16 +6843,19 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
vht_center_freq2, 0, ht40, vht,
- vht_chwidth, he, NULL, 0, 0);
+ vht_chwidth, he, edmg,
+ NULL, 0, 0, allow_6ghz);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
int freq = 0, persistent = 0, group_id = -1;
+ bool allow_6ghz = false;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
int he = wpa_s->conf->p2p_go_he;
+ int edmg = wpa_s->conf->p2p_go_edmg;
int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
#ifdef CONFIG_ACS
@@ -6449,8 +6880,12 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
ht40 = 1;
} else if (os_strcmp(token, "he") == 0) {
he = 1;
+ } else if (os_strcmp(token, "edmg") == 0) {
+ edmg = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
+ } else if (os_strcmp(token, "allow_6ghz") == 0) {
+ allow_6ghz = true;
} else {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
@@ -6486,10 +6921,11 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he,
+ edmg, allow_6ghz);
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he, edmg, allow_6ghz);
}
@@ -7075,7 +7511,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
return -1;
}
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
MAC2STR(bssid));
@@ -7110,7 +7546,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
{
u8 dst_addr[ETH_ALEN];
- int used;
+ int used, freq = 0;
char *pos;
#define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID];
@@ -7124,6 +7560,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
pos = dst + used;
if (*pos == ' ')
pos++;
+
+ if (os_strncmp(pos, "freq=", 5) == 0) {
+ freq = atoi(pos + 5);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+
while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
@@ -7158,7 +7603,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0 && !subtypes && !mbo_subtypes)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ return anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
mbo_subtypes);
}
@@ -7804,6 +8249,34 @@ static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
}
+static int wpas_ctrl_iface_driver_flags2(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags2);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags2 & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag2_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -7853,13 +8326,17 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
int ret;
- char *pos;
+ char *pos, *temp = NULL;
u8 *data = NULL;
unsigned int vendor_id, subcmd;
+ enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply;
size_t data_len = 0;
- /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ /**
+ * cmd: <vendor id> <subcommand id> [<hex formatted data>]
+ * [nested=<0|1>]
+ */
vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos))
return -EINVAL;
@@ -7869,7 +8346,9 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
if (*pos != '\0') {
if (!isblank((unsigned char) *pos++))
return -EINVAL;
- data_len = os_strlen(pos);
+
+ temp = os_strchr(pos, ' ');
+ data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
}
if (data_len) {
@@ -7886,6 +8365,11 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
}
}
+ pos = os_strstr(cmd, "nested=");
+ if (pos)
+ nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
+ NESTED_ATTR_NOT_USED;
+
reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) {
os_free(data);
@@ -7893,7 +8377,7 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
}
ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
- reply);
+ nested_attr_flag, reply);
if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
@@ -7964,12 +8448,21 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->dpp_resp_wait_time = 0;
wpa_s->dpp_resp_max_tries = 0;
wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
dpp_pkex_ephemeral_key_override_len = 0;
dpp_protocol_key_override_len = 0;
dpp_nonce_override_len = 0;
+#ifdef CONFIG_DPP2
+ dpp_version_override = 2;
+#else /* CONFIG_DPP2 */
+ dpp_version_override = 1;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
@@ -7983,9 +8476,12 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+ wpa_s->last_michael_mic_error.sec = 0;
wpa_s->no_keep_alive = 0;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
+ wpa_s->deny_ptk0_rekey = 0;
os_free(wpa_s->disallow_aps_bssid);
wpa_s->disallow_aps_bssid = NULL;
@@ -7997,22 +8493,24 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->set_sta_uapsd = 0;
wpa_s->sta_uapsd = 0;
+ wpa_s->consecutive_conn_failures = 0;
+
wpa_drv_radio_disable(wpa_s, 0);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_bssid_ignore_clear(wpa_s);
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
wpa_config_flush_blobs(wpa_s->conf);
wpa_s->conf->auto_interworking = 0;
wpa_s->conf->okc = 0;
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
rsn_preauth_deinit(wpa_s->wpa);
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
radio_remove_works(wpa_s, NULL, 1);
wpa_s->ext_work_in_progress = 0;
@@ -8034,13 +8532,32 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->p2p_go_csa_on_inv = 0;
wpa_s->ignore_auth_resp = 0;
wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->disable_sa_query = 0;
wpa_s->testing_resend_assoc = 0;
+ wpa_s->ignore_sae_h2e_only = 0;
+ wpa_s->ft_rsnxe_used = 0;
wpa_s->reject_btm_req_reason = 0;
wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
os_free(wpa_s->get_pref_freq_list_override);
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->sae_commit_override);
wpa_s->sae_commit_override = NULL;
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ wpa_s->rsnxe_override_assoc = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
+ wpa_s->oci_freq_override_eapol = 0;
+ wpa_s->oci_freq_override_saquery_req = 0;
+ wpa_s->oci_freq_override_saquery_resp = 0;
+ wpa_s->oci_freq_override_eapol_g2 = 0;
+ wpa_s->oci_freq_override_ft_assoc = 0;
+ wpa_s->oci_freq_override_fils_assoc = 0;
+ wpa_s->oci_freq_override_wnm_sleep = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8055,8 +8572,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->disconnected = 0;
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
os_free(wpa_s->select_network_scan_freqs);
wpa_s->select_network_scan_freqs = NULL;
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
wpa_bss_flush(wpa_s);
if (!dl_list_empty(&wpa_s->bss)) {
@@ -8073,6 +8593,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_SME
wpa_s->sme.last_unprot_disconnect.sec = 0;
+ wpa_s->sme.auth_alg = 0;
#endif /* CONFIG_SME */
wpabuf_free(wpa_s->ric_ies);
@@ -8081,6 +8602,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_supplicant_update_channel_list(wpa_s, NULL);
free_bss_tmp_disallowed(wpa_s);
+
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
+
+ if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0)
+ wpas_restore_permanent_mac_addr(wpa_s);
}
@@ -8389,6 +8919,9 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
goto done;
}
os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+
+ wpa_s->next_scan_bssid_wildcard_ssid =
+ os_strstr(params, "wildcard_ssid=1") != NULL;
}
pos = params;
@@ -8794,6 +9327,132 @@ fail:
}
+static int wpas_ctrl_iface_driver_event_assoc(struct wpa_supplicant *wpa_s,
+ char *param)
+{
+ union wpa_event_data event;
+ struct assoc_info *ai;
+ char *ctx = NULL;
+ int ret = -1;
+ struct wpabuf *req_ies = NULL;
+ struct wpabuf *resp_ies = NULL;
+ struct wpabuf *resp_frame = NULL;
+ struct wpabuf *beacon_ies = NULL;
+ struct wpabuf *key_replay_ctr = NULL;
+ struct wpabuf *ptk_kck = NULL;
+ struct wpabuf *ptk_kek = NULL;
+ struct wpabuf *fils_pmk = NULL;
+ char *str, *pos;
+ u8 addr[ETH_ALEN];
+ u8 fils_pmkid[PMKID_LEN];
+
+ os_memset(&event, 0, sizeof(event));
+ ai = &event.assoc_info;
+
+ while ((str = str_token(param, " ", &ctx))) {
+ pos = os_strchr(str, '=');
+ if (!pos)
+ goto fail;
+ *pos++ = '\0';
+
+ if (os_strcmp(str, "reassoc") == 0) {
+ ai->reassoc = atoi(pos);
+ } else if (os_strcmp(str, "req_ies") == 0) {
+ wpabuf_free(req_ies);
+ req_ies = wpabuf_parse_bin(pos);
+ if (!req_ies)
+ goto fail;
+ ai->req_ies = wpabuf_head(req_ies);
+ ai->req_ies_len = wpabuf_len(req_ies);
+ } else if (os_strcmp(str, "resp_ies") == 0) {
+ wpabuf_free(resp_ies);
+ resp_ies = wpabuf_parse_bin(pos);
+ if (!resp_ies)
+ goto fail;
+ ai->resp_ies = wpabuf_head(resp_ies);
+ ai->resp_ies_len = wpabuf_len(resp_ies);
+ } else if (os_strcmp(str, "resp_frame") == 0) {
+ wpabuf_free(resp_frame);
+ resp_frame = wpabuf_parse_bin(pos);
+ if (!resp_frame)
+ goto fail;
+ ai->resp_frame = wpabuf_head(resp_frame);
+ ai->resp_frame_len = wpabuf_len(resp_frame);
+ } else if (os_strcmp(str, "beacon_ies") == 0) {
+ wpabuf_free(beacon_ies);
+ beacon_ies = wpabuf_parse_bin(pos);
+ if (!beacon_ies)
+ goto fail;
+ ai->beacon_ies = wpabuf_head(beacon_ies);
+ ai->beacon_ies_len = wpabuf_len(beacon_ies);
+ } else if (os_strcmp(str, "freq") == 0) {
+ ai->freq = atoi(pos);
+ } else if (os_strcmp(str, "wmm::info_bitmap") == 0) {
+ ai->wmm_params.info_bitmap = atoi(pos);
+ } else if (os_strcmp(str, "wmm::uapsd_queues") == 0) {
+ ai->wmm_params.uapsd_queues = atoi(pos);
+ } else if (os_strcmp(str, "addr") == 0) {
+ if (hwaddr_aton(pos, addr))
+ goto fail;
+ ai->addr = addr;
+ } else if (os_strcmp(str, "authorized") == 0) {
+ ai->authorized = atoi(pos);
+ } else if (os_strcmp(str, "key_replay_ctr") == 0) {
+ wpabuf_free(key_replay_ctr);
+ key_replay_ctr = wpabuf_parse_bin(pos);
+ if (!key_replay_ctr)
+ goto fail;
+ ai->key_replay_ctr = wpabuf_head(key_replay_ctr);
+ ai->key_replay_ctr_len = wpabuf_len(key_replay_ctr);
+ } else if (os_strcmp(str, "ptk_kck") == 0) {
+ wpabuf_free(ptk_kck);
+ ptk_kck = wpabuf_parse_bin(pos);
+ if (!ptk_kck)
+ goto fail;
+ ai->ptk_kck = wpabuf_head(ptk_kck);
+ ai->ptk_kck_len = wpabuf_len(ptk_kck);
+ } else if (os_strcmp(str, "ptk_kek") == 0) {
+ wpabuf_free(ptk_kek);
+ ptk_kek = wpabuf_parse_bin(pos);
+ if (!ptk_kek)
+ goto fail;
+ ai->ptk_kek = wpabuf_head(ptk_kek);
+ ai->ptk_kek_len = wpabuf_len(ptk_kek);
+ } else if (os_strcmp(str, "subnet_status") == 0) {
+ ai->subnet_status = atoi(pos);
+ } else if (os_strcmp(str, "fils_erp_next_seq_num") == 0) {
+ ai->fils_erp_next_seq_num = atoi(pos);
+ } else if (os_strcmp(str, "fils_pmk") == 0) {
+ wpabuf_free(fils_pmk);
+ fils_pmk = wpabuf_parse_bin(pos);
+ if (!fils_pmk)
+ goto fail;
+ ai->fils_pmk = wpabuf_head(fils_pmk);
+ ai->fils_pmk_len = wpabuf_len(fils_pmk);
+ } else if (os_strcmp(str, "fils_pmkid") == 0) {
+ if (hexstr2bin(pos, fils_pmkid, PMKID_LEN) < 0)
+ goto fail;
+ ai->fils_pmkid = fils_pmkid;
+ } else {
+ goto fail;
+ }
+ }
+
+ wpa_supplicant_event(wpa_s, EVENT_ASSOC, &event);
+ ret = 0;
+fail:
+ wpabuf_free(req_ies);
+ wpabuf_free(resp_ies);
+ wpabuf_free(resp_frame);
+ wpabuf_free(beacon_ies);
+ wpabuf_free(key_replay_ctr);
+ wpabuf_free(ptk_kck);
+ wpabuf_free(ptk_kek);
+ wpabuf_free(fils_pmk);
+ return ret;
+}
+
+
static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *param;
@@ -8826,6 +9485,8 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
return 0;
} else if (os_strcmp(cmd, "SCAN_RES") == 0) {
return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
+ } else if (os_strcmp(cmd, "ASSOC") == 0) {
+ return wpas_ctrl_iface_driver_event_assoc(wpa_s, param);
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
cmd);
@@ -8876,6 +9537,45 @@ static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
}
+static int wpas_ctrl_iface_eapol_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 dst[ETH_ALEN], *buf;
+ int used, ret;
+ size_t len;
+ unsigned int prev;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (!buf || hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ prev = wpa_s->ext_eapol_frame_io;
+ wpa_s->ext_eapol_frame_io = 0;
+ ret = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, buf, len);
+ wpa_s->ext_eapol_frame_io = prev;
+ os_free(buf);
+
+ return ret;
+}
+
+
static u16 ipv4_hdr_checksum(const void *buf, size_t len)
{
size_t i;
@@ -8900,7 +9600,7 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip ip;
const u8 *pos;
unsigned int i;
char extra[30];
@@ -8916,14 +9616,13 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
- if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
- "test data: RX - ignore unexpect IP header");
+ "test data: RX - ignore unexpected IP header");
return;
}
- for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
@@ -8932,8 +9631,8 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
pos++;
}
extra[0] = '\0';
- if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
- os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -8985,7 +9684,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
@@ -9024,17 +9723,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- ip->tot_len = htons(send_len);
- ip->protocol = 1;
- ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
- ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
- ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
@@ -9227,13 +9926,15 @@ static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
* in the driver. */
if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- zero, wpa_s->last_tk_len) < 0)
+ zero, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- wpa_s->last_tk, wpa_s->last_tk_len);
+ wpa_s->last_tk, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -9285,6 +9986,103 @@ static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_SME */
}
+
+static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ u8 dtok = 1;
+ int exponent = 10;
+ int mantissa = 8192;
+ u8 min_twt = 255;
+ unsigned long long twt = 0;
+ bool requestor = true;
+ int setup_cmd = 0;
+ bool trigger = true;
+ bool implicit = true;
+ bool flow_type = true;
+ int flow_id = 0;
+ bool protection = false;
+ u8 twt_channel = 0;
+ u8 control = BIT(4); /* Control field (IEEE P802.11ax/D8.0 Figure
+ * 9-687): B4 = TWT Information Frame Disabled */
+ const char *tok_s;
+
+ tok_s = os_strstr(cmd, " dialog=");
+ if (tok_s)
+ dtok = atoi(tok_s + os_strlen(" dialog="));
+
+ tok_s = os_strstr(cmd, " exponent=");
+ if (tok_s)
+ exponent = atoi(tok_s + os_strlen(" exponent="));
+
+ tok_s = os_strstr(cmd, " mantissa=");
+ if (tok_s)
+ mantissa = atoi(tok_s + os_strlen(" mantissa="));
+
+ tok_s = os_strstr(cmd, " min_twt=");
+ if (tok_s)
+ min_twt = atoi(tok_s + os_strlen(" min_twt="));
+
+ tok_s = os_strstr(cmd, " setup_cmd=");
+ if (tok_s)
+ setup_cmd = atoi(tok_s + os_strlen(" setup_cmd="));
+
+ tok_s = os_strstr(cmd, " twt=");
+ if (tok_s)
+ sscanf(tok_s + os_strlen(" twt="), "%llu", &twt);
+
+ tok_s = os_strstr(cmd, " requestor=");
+ if (tok_s)
+ requestor = atoi(tok_s + os_strlen(" requestor="));
+
+ tok_s = os_strstr(cmd, " trigger=");
+ if (tok_s)
+ trigger = atoi(tok_s + os_strlen(" trigger="));
+
+ tok_s = os_strstr(cmd, " implicit=");
+ if (tok_s)
+ implicit = atoi(tok_s + os_strlen(" implicit="));
+
+ tok_s = os_strstr(cmd, " flow_type=");
+ if (tok_s)
+ flow_type = atoi(tok_s + os_strlen(" flow_type="));
+
+ tok_s = os_strstr(cmd, " flow_id=");
+ if (tok_s)
+ flow_id = atoi(tok_s + os_strlen(" flow_id="));
+
+ tok_s = os_strstr(cmd, " protection=");
+ if (tok_s)
+ protection = atoi(tok_s + os_strlen(" protection="));
+
+ tok_s = os_strstr(cmd, " twt_channel=");
+ if (tok_s)
+ twt_channel = atoi(tok_s + os_strlen(" twt_channel="));
+
+ tok_s = os_strstr(cmd, " control=");
+ if (tok_s)
+ control = atoi(tok_s + os_strlen(" control="));
+
+ return wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt,
+ setup_cmd, twt, requestor, trigger, implicit,
+ flow_type, flow_id, protection, twt_channel,
+ control);
+}
+
+
+static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ u8 flags = 0x1;
+ const char *tok_s;
+
+ tok_s = os_strstr(cmd, " flags=");
+ if (tok_s)
+ flags = atoi(tok_s + os_strlen(" flags="));
+
+ return wpas_twt_send_teardown(wpa_s, flags);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -9330,8 +10128,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_vendor_elem_update(wpa_s);
- return 0;
+ goto update_ies;
}
if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
@@ -9341,8 +10138,14 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
+
+update_ies:
wpas_vendor_elem_update(wpa_s);
+ if (frame == VENDOR_ELEM_PROBE_REQ ||
+ frame == VENDOR_ELEM_PROBE_REQ_P2P)
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -9455,16 +10258,16 @@ static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
nr_len < NR_IE_MIN_LEN) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%u",
- data[0], nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
goto out;
}
if (2U + nr_len > len) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
- data[0], len, nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
goto out;
}
pos += 2;
@@ -9534,8 +10337,8 @@ static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
ssid_s = os_strstr(cmd, "ssid=");
if (ssid_s) {
if (ssid_parse(ssid_s + 5, &ssid)) {
- wpa_printf(MSG_ERROR,
- "CTRL: Send Neighbor Report: bad SSID");
+ wpa_msg(wpa_s, MSG_INFO,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
}
@@ -9649,6 +10452,7 @@ static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
{
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
#ifdef CONFIG_AP
wpas_ap_pmksa_cache_flush(wpa_s);
@@ -9819,6 +10623,8 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
entry->network_ctx = ssid;
+ entry->external = true;
+
wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
entry = NULL;
ret = 0;
@@ -9853,7 +10659,7 @@ static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
char *cmd)
{
/*
- * We do not check mesh interface existance because PMKSA should be
+ * We do not check mesh interface existence because PMKSA should be
* stored before wpa_s->ifmsh creation to suppress commit message
* creation.
*/
@@ -9911,6 +10717,176 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd)
}
+static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ size_t frame_classifier_len;
+ const char *pos, *end;
+ struct robust_av_data *robust_av = &wpa_s->robust_av;
+ int val;
+
+ /*
+ * format:
+ * <add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>]
+ * [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>]
+ */
+ os_memset(robust_av, 0, sizeof(struct robust_av_data));
+ if (os_strncmp(cmd, "add ", 4) == 0) {
+ robust_av->request_type = SCS_REQ_ADD;
+ } else if (os_strcmp(cmd, "remove") == 0) {
+ robust_av->request_type = SCS_REQ_REMOVE;
+ robust_av->valid_config = false;
+ return wpas_send_mscs_req(wpa_s);
+ } else if (os_strncmp(cmd, "change ", 7) == 0) {
+ robust_av->request_type = SCS_REQ_CHANGE;
+ } else {
+ return -1;
+ }
+
+ pos = os_strstr(cmd, "up_bitmap=");
+ if (!pos)
+ return -1;
+
+ val = hex2byte(pos + 10);
+ if (val < 0)
+ return -1;
+ robust_av->up_bitmap = val;
+
+ pos = os_strstr(cmd, "up_limit=");
+ if (!pos)
+ return -1;
+
+ robust_av->up_limit = atoi(pos + 9);
+
+ pos = os_strstr(cmd, "stream_timeout=");
+ if (!pos)
+ return -1;
+
+ robust_av->stream_timeout = atoi(pos + 15);
+ if (robust_av->stream_timeout == 0)
+ return -1;
+
+ pos = os_strstr(cmd, "frame_classifier=");
+ if (!pos)
+ return -1;
+
+ pos += 17;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ frame_classifier_len = (end - pos) / 2;
+ if (frame_classifier_len > sizeof(robust_av->frame_classifier) ||
+ hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len))
+ return -1;
+
+ robust_av->frame_classifier_len = frame_classifier_len;
+ robust_av->valid_config = true;
+
+ return wpas_send_mscs_req(wpa_s);
+}
+
+
+#ifdef CONFIG_PASN
+static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *token, *context = NULL;
+ u8 bssid[ETH_ALEN];
+ int akmp = -1, cipher = -1, got_bssid = 0;
+ u16 group = 0xFFFF;
+ u8 *comeback = NULL;
+ size_t comeback_len = 0;
+ int id = 0, ret = -1;
+
+ /*
+ * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
+ * [comeback=<hexdump>]
+ */
+ while ((token = str_token(cmd, " ", &context))) {
+ if (os_strncmp(token, "bssid=", 6) == 0) {
+ if (hwaddr_aton(token + 6, bssid))
+ goto out;
+ got_bssid = 1;
+ } else if (os_strcmp(token, "akmp=PASN") == 0) {
+ akmp = WPA_KEY_MGMT_PASN;
+#ifdef CONFIG_IEEE80211R
+ } else if (os_strcmp(token, "akmp=FT-PSK") == 0) {
+ akmp = WPA_KEY_MGMT_FT_PSK;
+ } else if (os_strcmp(token, "akmp=FT-EAP-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ } else if (os_strcmp(token, "akmp=FT-EAP") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if (os_strcmp(token, "akmp=SAE") == 0) {
+ akmp = WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ } else if (os_strcmp(token, "akmp=FILS-SHA256") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA256;
+ } else if (os_strcmp(token, "akmp=FILS-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA384;
+#endif /* CONFIG_FILS */
+ } else if (os_strcmp(token, "cipher=CCMP-256") == 0) {
+ cipher = WPA_CIPHER_CCMP_256;
+ } else if (os_strcmp(token, "cipher=GCMP-256") == 0) {
+ cipher = WPA_CIPHER_GCMP_256;
+ } else if (os_strcmp(token, "cipher=CCMP") == 0) {
+ cipher = WPA_CIPHER_CCMP;
+ } else if (os_strcmp(token, "cipher=GCMP") == 0) {
+ cipher = WPA_CIPHER_GCMP;
+ } else if (os_strncmp(token, "group=", 6) == 0) {
+ group = atoi(token + 6);
+ } else if (os_strncmp(token, "nid=", 4) == 0) {
+ id = atoi(token + 4);
+ } else if (os_strncmp(token, "comeback=", 9) == 0) {
+ comeback_len = os_strlen(token + 9);
+ if (comeback || !comeback_len || comeback_len % 2)
+ goto out;
+
+ comeback_len /= 2;
+ comeback = os_malloc(comeback_len);
+ if (!comeback ||
+ hexstr2bin(token + 9, comeback, comeback_len))
+ goto out;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: PASN Invalid parameter: '%s'",
+ token);
+ goto out;
+ }
+ }
+
+ if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
+ wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+ goto out;
+ }
+
+ ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
+ comeback, comeback_len);
+out:
+ os_free(comeback);
+ return ret;
+}
+
+
+static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ u8 bssid[ETH_ALEN];
+
+ if (os_strncmp(cmd, "bssid=", 6) != 0 || hwaddr_aton(cmd + 6, bssid)) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: PASN_DEAUTH without valid BSSID");
+ return -1;
+ }
+
+ return wpas_pasn_deauthenticate(wpa_s, bssid);
+}
+
+#endif /* CONFIG_PASN */
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -10007,9 +10983,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
reply, reply_size);
} else if (os_strcmp(buf, "LOGON") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
} else if (os_strcmp(buf, "LOGOFF") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ eapol_sm_notify_logoff(wpa_s->eapol, true);
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
@@ -10369,8 +11345,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
reply_len = -1;
+ } else if (os_strncmp(buf, "BSSID_IGNORE", 12) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_bssid_ignore(
+ wpa_s, buf + 12, reply, reply_size);
} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
- reply_len = wpa_supplicant_ctrl_iface_blacklist(
+ /* deprecated backwards compatibility alias for BSSID_IGNORE */
+ reply_len = wpa_supplicant_ctrl_iface_bssid_ignore(
wpa_s, buf + 9, reply, reply_size);
} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
reply_len = wpa_supplicant_ctrl_iface_log_level(
@@ -10548,6 +11528,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags2(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -10590,6 +11573,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) {
+ if (wpas_ctrl_iface_eapol_tx(wpa_s, buf + 9) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
reply_len = -1;
@@ -10624,12 +11610,22 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
if (wpas_ctrl_resend_assoc(wpa_s) < 0)
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
sme_event_unprot_disconnect(
wpa_s, wpa_s->bssid, NULL,
WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
-#endif /* CONFIG_IEEE80211W */
+ } else if (os_strncmp(buf, "TWT_SETUP ", 10) == 0) {
+ if (wpas_ctrl_iface_send_twt_setup(wpa_s, buf + 9))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "TWT_SETUP") == 0) {
+ if (wpas_ctrl_iface_send_twt_setup(wpa_s, ""))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TWT_TEARDOWN ", 13) == 0) {
+ if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 12))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "TWT_TEARDOWN") == 0) {
+ if (wpas_ctrl_iface_send_twt_teardown(wpa_s, ""))
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -10670,6 +11666,39 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_uri(wpa_s, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
int res;
@@ -10698,6 +11727,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(wpa_s->dpp, atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -10751,8 +11784,34 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
dpp_controller_stop(wpa_s->dpp);
+ } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+ if (wpas_dpp_chirp(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ } else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
+ if (wpas_dpp_reconfig(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CA_SET ", 11) == 0) {
+ if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
+ reply_len = -1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ } else if (os_strncmp(buf, "MSCS ", 5) == 0) {
+ if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
+ reply_len = -1;
+#ifdef CONFIG_PASN
+ } else if (os_strncmp(buf, "PASN_START ", 11) == 0) {
+ if (wpas_ctrl_iface_pasn_start(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "PASN_STOP") == 0) {
+ wpas_pasn_auth_stop(wpa_s);
+ } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
+ reply_len = ptksa_cache_list(wpa_s->ptksa, reply, reply_size);
+ } else if (os_strncmp(buf, "PASN_DEAUTH ", 12) == 0) {
+ if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+#endif /* CONFIG_PASN */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.h b/contrib/wpa/wpa_supplicant/ctrl_iface.h
index d54cc076c447..dfbd25a03b1b 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface.h
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,10 @@
#ifdef CONFIG_CTRL_IFACE
+#ifndef CTRL_IFACE_MAX_LEN
+#define CTRL_IFACE_MAX_LEN 8192
+#endif /* CTRL_IFACE_MAX_LEN */
+
/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
/**
@@ -66,14 +70,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
/**
* wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
+ * @wpa_s: Pointer to wpa_supplicant data
* @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
*
* Deinitialize the control interface that was initialized with
- * wpa_supplicant_ctrl_iface_init().
+ * wpa_supplicant_ctrl_iface_init() and any data related to the wpa_s instance.
+ * @priv may be %NULL if the control interface has not yet been initialized.
*
* Required to be implemented in each control interface backend.
*/
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv);
/**
* wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
@@ -124,7 +131,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
static inline void
-wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
}
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
index 9c0a47e63936..bddc0414245e 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -45,7 +45,7 @@ ConvertStringSecurityDescriptorToSecurityDescriptorA
/* Per-interface ctrl_iface */
-#define REQUEST_BUFSIZE 256
+#define REQUEST_BUFSIZE CTRL_IFACE_MAX_LEN
#define REPLY_BUFSIZE 4096
struct ctrl_iface_priv;
@@ -462,8 +462,11 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
+ if (!priv)
+ return;
while (priv->ctrl_dst)
ctrl_close_pipe(priv->ctrl_dst);
if (priv->sec_attr_set)
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
index 8a6057a82bfe..1cbf7fa28d3f 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -219,7 +219,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[4096], *pos;
+ char *buf, *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
@@ -235,11 +235,15 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
int new_attached = 0;
u8 cookie[COOKIE_LEN];
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
return;
}
@@ -249,6 +253,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strcmp(addr, "::1")) {
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
addr);
+ os_free(buf);
+ return;
}
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
@@ -260,11 +266,17 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
*/
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
"source %s", inet_ntoa(from.sin_addr));
+ os_free(buf);
return;
}
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
+ return;
+ }
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -282,18 +294,21 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strncmp(buf, "COOKIE=", 7) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
"request - drop request");
+ os_free(buf);
return;
}
if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
@@ -339,6 +354,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
fromlen);
}
+ os_free(buf);
+
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
}
@@ -473,8 +490,12 @@ fail:
}
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
+ if (!priv)
+ return;
+
if (priv->sock > -1) {
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
@@ -516,7 +537,7 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
return;
if (ifname)
- os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+ os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>",
ifname, level);
else
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -600,10 +621,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[4096], *pos;
+ char *buf, *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -612,16 +636,28 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
size_t reply_len;
u8 cookie[COOKIE_LEN];
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
return;
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
-#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
+ if (os_strcmp(addr, "::1")) {
+ wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
+ addr);
+ os_free(buf);
+ return;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -631,11 +667,17 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
*/
wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
"source %s", inet_ntoa(from.sin_addr));
+ os_free(buf);
return;
}
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
+ return;
+ }
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -646,18 +688,21 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strncmp(buf, "COOKIE=", 7) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
"request - drop request");
+ os_free(buf);
return;
}
if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
"drop request");
+ os_free(buf);
return;
}
@@ -694,6 +739,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
fromlen);
}
+
+ os_free(buf);
}
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
index 71fe7ed6bef5..639573dae75e 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -131,7 +131,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[4096];
+ char *buf;
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
@@ -139,11 +139,20 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
size_t reply_len = 0;
int new_attached = 0;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
+ return;
+ }
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
return;
}
buf[res] = '\0';
@@ -221,6 +230,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
}
}
os_free(reply_buf);
+ os_free(buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -790,12 +800,52 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
}
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+static void
+wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global *global,
+ struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_global_priv *gpriv;
+ struct ctrl_iface_msg *msg, *prev_msg;
+ unsigned int count = 0;
+
+ if (!global || !global->ctrl_iface)
+ return;
+
+ gpriv = global->ctrl_iface;
+ dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ if (msg->wpa_s == wpa_s) {
+ count++;
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+ }
+
+ if (count) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Dropped %u pending message(s) for interface that is being removed",
+ count);
+ }
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
struct wpa_ctrl_dst *dst, *prev;
struct ctrl_iface_msg *msg, *prev_msg;
struct ctrl_iface_global_priv *gpriv;
+ if (!priv) {
+ /* Control interface has not yet been initialized, so there is
+ * nothing to deinitialize here. However, there might be a
+ * pending message for this interface, so get rid of any such
+ * entry before completing interface removal. */
+ wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
+ eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+ return;
+ }
+
if (priv->sock > -1) {
char *fname;
char *buf, *dir = NULL;
@@ -867,6 +917,7 @@ free_dst:
}
}
}
+ wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
os_free(priv);
}
@@ -1046,18 +1097,27 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[4096];
+ char *buf;
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
+ if (!buf)
+ return;
+ res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
strerror(errno));
+ os_free(buf);
+ return;
+ }
+ if ((size_t) res > CTRL_IFACE_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
+ os_free(buf);
return;
}
buf[res] = '\0';
@@ -1105,6 +1165,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
}
}
os_free(reply_buf);
+ os_free(buf);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
index efa6c7b20595..a727217fd6f9 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
@@ -108,17 +108,18 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
flags = dbus_watch_get_flags(watch);
fd = dbus_watch_get_unix_fd(watch);
- eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
- priv, watch);
-
- if (flags & DBUS_WATCH_READABLE) {
- eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
- priv, watch);
- }
- if (flags & DBUS_WATCH_WRITABLE) {
- eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
- priv, watch);
- }
+ if (eloop_register_sock(fd, EVENT_TYPE_EXCEPTION,
+ process_watch_exception, priv, watch) < 0)
+ return FALSE;
+
+ if ((flags & DBUS_WATCH_READABLE) &&
+ eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
+ priv, watch) < 0)
+ return FALSE;
+ if ((flags & DBUS_WATCH_WRITABLE) &&
+ eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
+ priv, watch) < 0)
+ return FALSE;
dbus_watch_set_data(watch, priv, NULL);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
index fc2fc2ef1b96..2c01943f754e 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
@@ -750,10 +750,12 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
if (cred->auth_type & WPS_AUTH_OPEN)
auth_type[at_num++] = "open";
+#ifndef CONFIG_NO_TKIP
if (cred->auth_type & WPS_AUTH_WPAPSK)
auth_type[at_num++] = "wpa-psk";
if (cred->auth_type & WPS_AUTH_WPA)
auth_type[at_num++] = "wpa-eap";
+#endif /* CONFIG_NO_TKIP */
if (cred->auth_type & WPS_AUTH_WPA2)
auth_type[at_num++] = "wpa2-eap";
if (cred->auth_type & WPS_AUTH_WPA2PSK)
@@ -761,8 +763,10 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
if (cred->encr_type & WPS_ENCR_NONE)
encr_type[et_num++] = "none";
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
encr_type[et_num++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (cred->encr_type & WPS_ENCR_AES)
encr_type[et_num++] = "aes";
@@ -1820,7 +1824,7 @@ void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
* @sa: station addr (p2p i/f) of the peer
* @dialog_token: service discovery request dialog token
* @update_indic: service discovery request update indicator
- * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs: service discovery request generated byte array of tlvs
* @tlvs_len: service discovery request tlvs length
*/
void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
@@ -1889,7 +1893,7 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
* @wpa_s: %wpa_supplicant network interface data
* @sa: station addr (p2p i/f) of the peer
* @update_indic: service discovery request update indicator
- * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs: service discovery request generated byte array of tlvs
* @tlvs_len: service discovery request tlvs length
*/
void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
@@ -2855,30 +2859,6 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
NULL,
NULL
},
- {
- "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_roam_time,
- NULL,
- NULL
- },
- {
- "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
- wpas_dbus_getter_roam_complete,
- NULL,
- NULL
- },
- {
- "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_session_length,
- NULL,
- NULL
- },
- {
- "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_bss_tm_status,
- NULL,
- NULL
- },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -3232,6 +3212,14 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Roam", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_roam,
+ {
+ { "addr", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+
#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_add_blob,
@@ -3633,7 +3621,7 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_bridge_ifname,
- NULL,
+ wpas_dbus_setter_bridge_ifname,
NULL
},
{ "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
@@ -3786,6 +3774,30 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL,
NULL
},
+ {
+ "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_roam_time,
+ NULL,
+ NULL
+ },
+ {
+ "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_roam_complete,
+ NULL,
+ NULL
+ },
+ {
+ "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_session_length,
+ NULL,
+ NULL
+ },
+ {
+ "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_tm_status,
+ NULL,
+ NULL
+ },
#ifdef CONFIG_MESH
{ "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
wpas_dbus_getter_mesh_peers,
@@ -3803,6 +3815,12 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL,
NULL
},
+ { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "a{say}",
+ wpas_dbus_getter_mac_address_randomization_mask,
+ wpas_dbus_setter_mac_address_randomization_mask,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4791,8 +4809,8 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
if (!wpa_s->dbus_groupobj_path) {
wpa_printf(MSG_DEBUG,
- "%s: Group object '%s' already unregistered",
- __func__, wpa_s->dbus_groupobj_path);
+ "%s: Group object has already unregistered",
+ __func__);
return;
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
index 6c36d91a0cf8..db9f30c9aabf 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -137,8 +137,18 @@ DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
static const char * const dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
- "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", "scan_freq", "freq_list", NULL
+ "bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
+ "bssid_ignore", "bssid_accept", /* deprecated aliases */
+ "bssid_blacklist", "bssid_whitelist",
+ "group_mgmt",
+ "ignore_broadcast_ssid",
+#ifdef CONFIG_MESH
+ "mesh_basic_rates",
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_P2P
+ "go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+ NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -222,8 +232,6 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
} else if (entry.type == DBUS_TYPE_STRING) {
if (should_quote_opt(entry.key)) {
size = os_strlen(entry.str_value);
- if (size == 0)
- goto error;
size += 3;
value = os_zalloc(size);
@@ -260,8 +268,28 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
} else
goto error;
- if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+ ret = wpa_config_set(ssid, entry.key, value, 0);
+ if (ret < 0)
goto error;
+ if (ret == 1)
+ goto skip_update;
+
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(entry.key, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network
+ * and continue. There's no need to flush caches for
+ * bgscan parameter changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ os_free(value);
+ value = NULL;
+ wpa_dbus_dict_entry_clear(&entry);
+ continue;
+ }
+#endif /* CONFIG_BGSCAN */
if (os_strcmp(entry.key, "bssid") != 0 &&
os_strcmp(entry.key, "priority") != 0)
@@ -283,6 +311,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ skip_update:
os_free(value);
value = NULL;
wpa_dbus_dict_entry_clear(&entry);
@@ -984,21 +1013,25 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ const char *capabilities[13];
size_t num_items = 0;
-#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
+#ifdef CONFIG_FILS
int fils_supported = 0, fils_sk_pfs_supported = 0;
+#endif /* CONFIG_FILS */
+ int ext_key_id_supported = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+#ifdef CONFIG_FILS
if (wpa_is_fils_supported(wpa_s))
fils_supported = 1;
if (wpa_is_fils_sk_pfs_supported(wpa_s))
fils_sk_pfs_supported = 1;
- }
#endif /* CONFIG_FILS */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
+ ext_key_id_supported = 1;
+ }
#ifdef CONFIG_AP
capabilities[num_items++] = "ap";
@@ -1012,9 +1045,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_IEEE80211W
capabilities[num_items++] = "pmf";
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MESH
capabilities[num_items++] = "mesh";
#endif /* CONFIG_MESH */
@@ -1030,6 +1061,14 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_SHA384
capabilities[num_items++] = "sha384";
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_OWE
+ capabilities[num_items++] = "owe";
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_SUITEB192
+ capabilities[num_items++] = "suiteb192";
+#endif /* CONFIG_SUITEB192 */
+ if (ext_key_id_supported)
+ capabilities[num_items++] = "extended_key_id";
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -1139,7 +1178,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
DBusMessage **reply)
{
u8 *ies = NULL, *nies;
- int ies_len = 0;
+ size_t ies_len = 0;
DBusMessageIter array_iter, sub_array_iter;
char *val;
int len;
@@ -1170,7 +1209,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
- if (len == 0) {
+ if (len <= 0) {
dbus_message_iter_next(&array_iter);
continue;
}
@@ -1201,7 +1240,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
{
DBusMessageIter array_iter, sub_array_iter;
int *freqs = NULL, *nfreqs;
- int freqs_num = 0;
+ size_t freqs_num = 0;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
wpa_printf(MSG_DEBUG,
@@ -1663,7 +1702,8 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
* Returns: NULL
*
* Handler function for notifying system there will be a expected disconnect.
- * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
+ * This will prevent wpa_supplicant from adding the BSSID to the ignore list
+ * upon next disconnect.
*/
DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
struct wpa_global *global)
@@ -1783,25 +1823,6 @@ out:
}
-static void remove_network(void *arg, struct wpa_ssid *ssid)
-{
- struct wpa_supplicant *wpa_s = arg;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
- wpa_printf(MSG_ERROR,
- "%s[dbus]: error occurred when removing network %d",
- __func__, ssid->id);
- return;
- }
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-}
-
-
/**
* wpas_dbus_handler_remove_all_networks - Remove all configured networks
* @message: Pointer to incoming dbus message
@@ -1813,11 +1834,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
/* NB: could check for failure and return an error */
- wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+ wpa_supplicant_remove_all_networks(wpa_s);
return NULL;
}
@@ -1942,6 +1960,65 @@ out:
}
+/**
+ * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "Roam" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return wpas_dbus_error_unknown_error(message,
+ "scan processing not included");
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ u8 bssid[ETH_ALEN];
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ char *addr;
+ struct wpa_radio_work *already_connecting;
+
+ if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (hwaddr_aton(addr, bssid))
+ return wpas_dbus_error_invalid_args(
+ message, "Invalid hardware address format");
+
+ wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
+
+ if (!ssid)
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
+ return wpas_dbus_error_invalid_args(
+ message, "Target BSS not found");
+ }
+
+ already_connecting = radio_work_pending(wpa_s, "sme-connect");
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+
+ /*
+ * Indicate that an explicitly requested roam is in progress so scan
+ * results that come in before the 'sme-connect' radio work gets
+ * executed do not override the original connection attempt.
+ */
+ if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
+ wpa_s->roam_in_progress = true;
+
+ return NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
@@ -2507,7 +2584,7 @@ wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
* wpas_dbus_handler_save_config - Save configuration to configuration file
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL on Success, Otherwise errror message
+ * Returns: NULL on Success, Otherwise error message
*
* Handler function for "SaveConfig" method call of network interface.
*/
@@ -2618,7 +2695,11 @@ dbus_bool_t wpas_dbus_getter_capabilities(
/***** pairwise cipher */
if (res < 0) {
+#ifdef CONFIG_NO_TKIP
+ const char *args[] = {"ccmp", "none"};
+#else /* CONFIG_NO_TKIP */
const char *args[] = {"ccmp", "tkip", "none"};
+#endif /* CONFIG_NO_TKIP */
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
@@ -2641,9 +2722,11 @@ dbus_bool_t wpas_dbus_getter_capabilities(
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_TKIP */
((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "none")) ||
@@ -2657,7 +2740,13 @@ dbus_bool_t wpas_dbus_getter_capabilities(
/***** group cipher */
if (res < 0) {
const char *args[] = {
- "ccmp", "tkip", "wep104", "wep40"
+ "ccmp",
+#ifndef CONFIG_NO_TKIP
+ "tkip",
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
+ "wep104", "wep40"
+#endif /* CONFIG_WEP */
};
if (!wpa_dbus_dict_append_string_array(
@@ -2681,15 +2770,19 @@ dbus_bool_t wpas_dbus_getter_capabilities(
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "wep104")) ||
((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "wep40")) ||
+#endif /* CONFIG_WEP */
!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -2753,11 +2846,9 @@ dbus_bool_t wpas_dbus_getter_capabilities(
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-eap-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
@@ -2771,11 +2862,9 @@ dbus_bool_t wpas_dbus_getter_capabilities(
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-psk-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
@@ -2790,6 +2879,18 @@ dbus_bool_t wpas_dbus_getter_capabilities(
goto nomem;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
+ goto nomem;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_OWE
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array, "owe"))
+ goto nomem;
+#endif /* CONFIG_OWE */
+
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -3602,6 +3703,43 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(
}
+dbus_bool_t wpas_dbus_setter_bridge_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *bridge_ifname = NULL;
+ const char *msg;
+ int r;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &bridge_ifname))
+ return FALSE;
+
+ r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
+ if (r != 0) {
+ switch (r) {
+ case -EINVAL:
+ msg = "invalid interface name";
+ break;
+ case -EBUSY:
+ msg = "interface is busy";
+ break;
+ case -EIO:
+ msg = "socket error";
+ break;
+ default:
+ msg = "unknown error";
+ break;
+ }
+ dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
/**
* wpas_dbus_getter_config_file - Get interface configuration file path
* @iter: Pointer to incoming dbus message iter
@@ -3909,14 +4047,15 @@ dbus_bool_t wpas_dbus_setter_iface_global(
return FALSE;
}
- if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+ ret = wpa_config_process_global(wpa_s->conf, buf, -1);
+ if (ret < 0) {
dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
"Failed to set interface property %s",
property_desc->dbus_property);
return FALSE;
+ } else if (ret == 0) {
+ wpa_supplicant_update_config(wpa_s);
}
-
- wpa_supplicant_update_config(wpa_s);
return TRUE;
}
@@ -3990,6 +4129,173 @@ out:
/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ const char *key;
+ unsigned int rand_type = 0;
+ const u8 *mask;
+ int mask_len;
+ unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+ dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&variant_iter, &dict_iter);
+ while (dbus_message_iter_get_arg_type(&dict_iter) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_STRING) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: key not a string", __func__);
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry_iter, &key);
+ dbus_message_iter_next(&entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&entry_iter) !=
+ DBUS_TYPE_BYTE) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: mask was not a byte array",
+ __func__);
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&entry_iter, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &mask,
+ &mask_len);
+
+ if (os_strcmp(key, "scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCAN;
+ } else if (os_strcmp(key, "sched_scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcmp(key, "pno") == 0) {
+ rand_type = MAC_ADDR_RAND_PNO;
+ } else {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: bad scan type \"%s\"",
+ __func__, key);
+ return FALSE;
+ }
+
+ if (mask_len != ETH_ALEN) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: malformed MAC mask given",
+ __func__);
+ return FALSE;
+ }
+
+ if (wpas_enable_mac_addr_randomization(
+ wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to set up MAC address randomization for %s",
+ __func__, key);
+ return FALSE;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: Enabled MAC address randomization for %s with mask: "
+ MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+ rand_types_to_disable &= ~rand_type;
+ dbus_message_iter_next(&dict_iter);
+ }
+
+ if (rand_types_to_disable &&
+ wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to disable MAC address randomization",
+ __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ unsigned int i;
+ u8 mask_buf[ETH_ALEN];
+ /* Read docs on dbus_message_iter_append_fixed_array() for why this
+ * is necessary... */
+ u8 *mask = mask_buf;
+ static const struct {
+ const char *key;
+ unsigned int type;
+ } types[] = {
+ { "scan", MAC_ADDR_RAND_SCAN },
+ { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+ { "pno", MAC_ADDR_RAND_PNO }
+ };
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{say}", &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
+ mask))
+ continue;
+
+ if (!dbus_message_iter_open_container(&dict_iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
+ DBUS_TYPE_STRING,
+ &types[i].key) ||
+ !dbus_message_iter_open_container(&entry_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE,
+ &mask,
+ ETH_ALEN) ||
+ !dbus_message_iter_close_container(&entry_iter,
+ &array_iter) ||
+ !dbus_message_iter_close_container(&dict_iter,
+ &entry_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ return FALSE;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_sta_address - Return the address of a connected station
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -4497,7 +4803,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[15]; /* max 15 key managements may be supported */
+ const char *key_mgmt[16]; /* max 16 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4550,6 +4856,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
+ key_mgmt[n++] = "owe";
+#endif /* CONFIG_OWE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -4559,21 +4869,25 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
/* Group */
switch (ie_data->group_cipher) {
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
group = "wep40";
break;
+ case WPA_CIPHER_WEP104:
+ group = "wep104";
+ break;
+#endif /* CONFIG_WEP */
+#ifndef CONFIG_NO_TKIP
case WPA_CIPHER_TKIP:
group = "tkip";
break;
+#endif /* CONFIG_NO_TKIP */
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
case WPA_CIPHER_GCMP:
group = "gcmp";
break;
- case WPA_CIPHER_WEP104:
- group = "wep104";
- break;
case WPA_CIPHER_CCMP_256:
group = "ccmp-256";
break;
@@ -4590,8 +4904,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
/* Pairwise */
n = 0;
+#ifndef CONFIG_NO_TKIP
if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
pairwise[n++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
@@ -4608,11 +4924,9 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
/* Management group (RSN only) */
if (ie_data->proto == WPA_PROTO_RSN) {
switch (ie_data->mgmt_group_cipher) {
-#ifdef CONFIG_IEEE80211W
case WPA_CIPHER_AES_128_CMAC:
group = "aes128cmac";
break;
-#endif /* CONFIG_IEEE80211W */
default:
group = "";
break;
@@ -4781,8 +5095,8 @@ dbus_bool_t wpas_dbus_getter_bss_ies(
return FALSE;
return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
- res + 1, res->ie_len,
- error);
+ wpa_bss_ie_ptr(res),
+ res->ie_len, error);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1b4189..c36383f05668 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -117,6 +117,9 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -167,6 +170,7 @@ DECLARE_ACCESSOR(wpas_dbus_setter_scan_interval);
DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_driver);
DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_setter_bridge_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
@@ -177,6 +181,8 @@ DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 8cdd885644af..565ced0fd7e2 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -40,6 +40,14 @@ static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
}
+static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
+{
+ dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+ return FALSE;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +86,22 @@ wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
}
+/**
+ * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
+ * message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an unknown interface error.
+ */
+static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
@@ -145,9 +169,13 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto error_nop2p;
+ }
if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
- req_dev_types, NULL, 0, 0, NULL, freq))
+ req_dev_types, NULL, 0, 0, NULL, freq, false))
reply = wpas_dbus_error_unknown_error(
message, "Could not start P2P find");
@@ -157,8 +185,9 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
- os_free(req_dev_types);
reply = wpas_dbus_error_invalid_args(message, entry.key);
+error_nop2p:
+ os_free(req_dev_types);
return reply;
}
@@ -166,7 +195,9 @@ error:
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (wpa_s)
+ wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -185,6 +216,8 @@ DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -204,6 +237,8 @@ DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
return wpas_dbus_error_no_memory(message);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
return dbus_message_new_error(message,
@@ -245,6 +280,8 @@ DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
@@ -350,6 +387,10 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
if (pg_object_path != NULL) {
char *net_id_str;
@@ -384,14 +425,15 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- 0, 0, 0, NULL, 0, 0)) {
+ 0, 0, 0, 0, NULL, 0, 0,
+ false)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
- 0, 0))
+ 0, 0, 0, false))
goto inv_args;
out:
@@ -433,6 +475,12 @@ static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
"P2P is not available for this interface");
return FALSE;
}
+ if (!wpa_s->global->p2p_init_wpa_s) {
+ if (out_reply)
+ *out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
+ message);
+ return no_p2p_mgmt_interface(error);
+ }
return TRUE;
}
@@ -605,8 +653,8 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
- NULL, 0);
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
+ NULL, 0, false);
if (new_pin >= 0) {
char npin[9];
@@ -763,7 +811,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0, 0) < 0) {
+ 0, 0, 0, false) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -774,7 +822,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
* No group ID means propose to a peer to join my active group
*/
if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
- peer_addr, NULL)) {
+ peer_addr, NULL, false)) {
reply = wpas_dbus_error_unknown_error(
message, "Failed to join to an active group");
goto out;
@@ -822,6 +870,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
@@ -1882,6 +1932,8 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
wpa_s = peer_args->wpa_s;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
@@ -1963,6 +2015,9 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(
dbus_bool_t success = FALSE;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
+
if (!wpa_s->parent->dbus_new_path)
return FALSE;
@@ -2077,6 +2132,11 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
dbus_message_iter_init(message, &iter);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto err;
+ }
+
if (wpa_s->parent->dbus_new_path)
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -2159,6 +2219,10 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
DBUS_TYPE_INVALID);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
/*
* Extract the network ID and ensure the network is actually a child of
@@ -2235,6 +2299,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
struct wpa_config *config;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
config = wpa_s->conf;
ssid = config->ssid;
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
index aee105b4b54c..6c721bf556db 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
DBusMessage *reply;
struct wpabuf *xml;
- xml = wpabuf_alloc(20000);
+ xml = wpabuf_alloc(30000);
if (xml == NULL)
return NULL;
diff --git a/contrib/wpa/wpa_supplicant/defconfig b/contrib/wpa/wpa_supplicant/defconfig
index cdfb1974da5c..708a82385170 100644
--- a/contrib/wpa/wpa_supplicant/defconfig
+++ b/contrib/wpa/wpa_supplicant/defconfig
@@ -77,7 +77,7 @@ CONFIG_DRIVER_WIRED=y
#CONFIG_DRIVER_MACSEC_QCA=y
# Driver interface for Linux MACsec drivers
-#CONFIG_DRIVER_MACSEC_LINUX=y
+CONFIG_DRIVER_MACSEC_LINUX=y
# Driver interface for the Broadcom RoboSwitch family
#CONFIG_DRIVER_ROBOSWITCH=y
@@ -183,7 +183,7 @@ CONFIG_EAP_IKEV2=y
#CONFIG_EAP_EKE=y
# MACsec
-#CONFIG_MACSEC=y
+CONFIG_MACSEC=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
@@ -248,7 +248,7 @@ CONFIG_CTRL_IFACE=y
# Simultaneous Authentication of Equals (SAE), WPA3-Personal
CONFIG_SAE=y
-# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# Disable scan result processing (ap_scan=1) to save code size by about 1 kB.
# This can be used if ap_scan=1 mode is never enabled.
#CONFIG_NO_SCAN_PROCESSING=y
@@ -310,10 +310,6 @@ CONFIG_BACKEND=file
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -366,7 +362,7 @@ CONFIG_IEEE80211W=y
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
+# (fi.w1.wpa_supplicant1)
CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
@@ -475,11 +471,7 @@ CONFIG_DEBUG_SYSLOG=y
# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
#CONFIG_GETRANDOM=y
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -514,7 +506,7 @@ CONFIG_AP=y
CONFIG_P2P=y
# Enable TDLS support
-#CONFIG_TDLS=y
+CONFIG_TDLS=y
# Wi-Fi Display
# This can be used to enable Wi-Fi Display extensions for P2P using an external
@@ -538,6 +530,8 @@ CONFIG_WIFI_DISPLAY=y
#
# External password backend for testing purposes (developer use)
#CONFIG_EXT_PASSWORD_TEST=y
+# File-based backend to read passwords from an external file.
+#CONFIG_EXT_PASSWORD_FILE=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
@@ -610,6 +604,27 @@ CONFIG_BGSCAN_SIMPLE=y
#CONFIG_OWE=y
# Device Provisioning Protocol (DPP)
-# This requires CONFIG_IEEE80211W=y to be enabled, too. (see
-# wpa_supplicant/README-DPP for details)
CONFIG_DPP=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
+# Remove all TKIP functionality
+# TKIP is an old cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used anymore for anything else than a
+# backwards compatibility option as a group cipher when connecting to APs that
+# use WPA+WPA2 mixed mode. For now, the default wpa_supplicant build includes
+# support for this by default, but that functionality is subject to be removed
+# in the future.
+#CONFIG_NO_TKIP=y
+
+# Pre-Association Security Negotiation (PASN)
+# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
+# design is still subject to change. As such, this should not yet be enabled in
+# production use.
+#CONFIG_PASN=y
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/Makefile b/contrib/wpa/wpa_supplicant/doc/docbook/Makefile
new file mode 100644
index 000000000000..82f9de315dc5
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/Makefile
@@ -0,0 +1,28 @@
+all: man html pdf
+
+FILES += wpa_background
+FILES += wpa_cli
+FILES += wpa_gui
+FILES += wpa_passphrase
+FILES += wpa_priv
+FILES += wpa_supplicant.conf
+FILES += wpa_supplicant
+FILES += eapol_test
+
+man:
+ for i in $(FILES); do docbook2man $$i.sgml; done
+
+html:
+ for i in $(FILES); do docbook2html $$i.sgml && \
+ mv index.html $$i.html; done
+
+pdf:
+ for i in $(FILES); do docbook2pdf $$i.sgml; done
+
+
+clean:
+ rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8 eapol_test.8
+ rm -f wpa_supplicant.conf.5
+ rm -f manpage.links manpage.refs
+ rm -f $(FILES:%=%.pdf)
+ rm -f $(FILES:%=%.html)
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/eapol_test.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/eapol_test.sgml
new file mode 100644
index 000000000000..4cfa3c1db384
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -0,0 +1,209 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>eapol_test</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>eapol_test</refname>
+
+ <refpurpose>EAP peer and RADIUS client testing</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>eapol_test</command>
+ <arg>-nWS</arg>
+ <arg>-c<replaceable>config file</replaceable></arg>
+ <arg>-a<replaceable>server IP address</replaceable></arg>
+ <arg>-A<replaceable>client IP address</replaceable></arg>
+ <arg>-p<replaceable>UDP port</replaceable></arg>
+ <arg>-s<replaceable>shared secret</replaceable></arg>
+ <arg>-r<replaceable>re-authentications</replaceable></arg>
+ <arg>-t<replaceable>timeout</replaceable></arg>
+ <arg>-C<replaceable>Connect-Info</replaceable></arg>
+ <arg>-M<replaceable>MAC address</replaceable></arg>
+ <arg>-o<replaceable>file</replaceable></arg>
+ <arg>-N<replaceable>attr spec</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>eapol_test scard</command>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>eapol_test sim</command>
+ <arg>PIN</arg>
+ <arg>num triplets</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para>eapol_test is a program that links together the same EAP
+ peer implementation that wpa_supplicant is using and the RADIUS
+ authentication client code from hostapd. In addition, it has
+ minimal glue code to combine these two components in similar
+ ways to IEEE 802.1X/EAPOL Authenticator state machines. In other
+ words, it integrates IEEE 802.1X Authenticator (normally, an
+ access point) and IEEE 802.1X Supplicant (normally, a wireless
+ client) together to generate a single program that can be used to
+ test EAP methods without having to setup an access point and a
+ wireless client.</para>
+
+ <para>The main uses for eapol_test are in interoperability testing
+ of EAP methods against RADIUS servers and in development testing
+ for new EAP methods. It can be easily used to automate EAP testing
+ for interoperability and regression since the program can be run
+ from shell scripts without require additional test components apart
+ from a RADIUS server. For example, the automated EAP tests described
+ in eap_testing.txt are implemented with eapol_test. Similarly,
+ eapol_test could be used to implement an automated regression
+ test suite for a RADIUS authentication server.</para>
+
+
+ <para>As an example:</para>
+
+<blockquote><programlisting>
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+</programlisting></blockquote>
+
+ <para>tries to complete EAP authentication based on the network
+ configuration from test.conf against the RADIUS server running
+ on the local host. A re-authentication is triggered to test fast
+ re-authentication. The configuration file uses the same format for
+ network blocks as wpa_supplicant.</para>
+
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-c configuration file path</term>
+
+ <listitem><para>A configuration to use. The configuration should
+ use the same format for network blocks as wpa_supplicant.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a AS address</term>
+
+ <listitem><para>IP address of the authentication server. The
+ default is '127.0.0.1'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-A client address</term>
+
+ <listitem><para>IP address of the client. The default is to
+ select an address automatically.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-p AS port</term>
+
+ <listitem><para>UDP port of the authentication server. The
+ default is '1812'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s AS secret</term>
+
+ <listitem><para>Shared secret with the authentication server.
+ The default is 'radius'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-r count</term>
+
+ <listitem><para>Number of reauthentications.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t timeout</term>
+
+ <listitem><para>Timeout in seconds. The default is 30.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-C info</term>
+
+ <listitem><para>RADIUS Connect-Info. The default is
+ 'CONNECT 11Mbps 802.11b'.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-M mac address</term>
+
+ <listitem><para>Client MAC address (Calling-Station-Id). The
+ default is '02:00:00:00:00:01'.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o file</term>
+
+ <listitem><para>Location to write out server certificate.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-N attr spec</term>
+
+ <listitem><para>Send arbitrary attribute specific by
+ attr_id:syntax:value, or attr_id alone. attr_id should be the numeric
+ ID of the attribute, and syntax should be one of 's' (string),
+ 'd' (integer), or 'x' (octet string). The value is the attribute value
+ to send. When attr_id is given alone, NULL is used as the attribute
+ value. Multiple attributes can be specified by using the option
+ several times.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-n</term>
+
+ <listitem><para>Indicates that no MPPE keys are expected.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-W</term>
+
+ <listitem><para>Wait for a control interface monitor before starting.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S</term>
+
+ <listitem><para>Save configuration after authentication.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_background.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_background.sgml
new file mode 100644
index 000000000000..22241ccf9006
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -0,0 +1,105 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_background</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_background</refname>
+ <refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>WPA</title>
+
+ <para>The original security mechanism of IEEE 802.11 standard was
+ not designed to be strong and has proven to be insufficient for
+ most networks that require some kind of security. Task group I
+ (Security) of IEEE 802.11 working group
+ (http://www.ieee802.org/11/) has worked to address the flaws of
+ the base standard and has in practice completed its work in May
+ 2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
+ approved in June 2004 and published in July 2004.</para>
+
+ <para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
+ of the IEEE 802.11i work (draft 3.0) to define a subset of the
+ security enhancements that can be implemented with existing wlan
+ hardware. This is called Wi-Fi Protected Access&lt;TM&gt; (WPA). This
+ has now become a mandatory component of interoperability testing
+ and certification done by Wi-Fi Alliance. Wi-Fi provides
+ information about WPA at its web site
+ (http://www.wi-fi.org/OpenSection/protected_access.asp).</para>
+
+ <para>IEEE 802.11 standard defined wired equivalent privacy (WEP)
+ algorithm for protecting wireless networks. WEP uses RC4 with
+ 40-bit keys, 24-bit initialization vector (IV), and CRC32 to
+ protect against packet forgery. All these choices have proven to
+ be insufficient: key space is too small against current attacks,
+ RC4 key scheduling is insufficient (beginning of the pseudorandom
+ stream should be skipped), IV space is too small and IV reuse
+ makes attacks easier, there is no replay protection, and non-keyed
+ authentication does not protect against bit flipping packet
+ data.</para>
+
+ <para>WPA is an intermediate solution for the security issues. It
+ uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
+ is a compromise on strong security and possibility to use existing
+ hardware. It still uses RC4 for the encryption like WEP, but with
+ per-packet RC4 keys. In addition, it implements replay protection,
+ keyed packet authentication mechanism (Michael MIC).</para>
+
+ <para>Keys can be managed using two different mechanisms. WPA can
+ either use an external authentication server (e.g., RADIUS) and
+ EAP just like IEEE 802.1X is using or pre-shared keys without need
+ for additional servers. Wi-Fi calls these "WPA-Enterprise" and
+ "WPA-Personal", respectively. Both mechanisms will generate a
+ master session key for the Authenticator (AP) and Supplicant
+ (client station).</para>
+
+ <para>WPA implements a new key handshake (4-Way Handshake and
+ Group Key Handshake) for generating and exchanging data encryption
+ keys between the Authenticator and Supplicant. This handshake is
+ also used to verify that both Authenticator and Supplicant know
+ the master session key. These handshakes are identical regardless
+ of the selected key management mechanism (only the method for
+ generating master session key changes).</para>
+ </refsect1>
+
+ <refsect1>
+ <title>IEEE 802.11i / WPA2</title>
+
+ <para>The design for parts of IEEE 802.11i that were not included
+ in WPA has finished (May 2004) and this amendment to IEEE 802.11
+ was approved in June 2004. Wi-Fi Alliance is using the final IEEE
+ 802.11i as a new version of WPA called WPA2. This includes, e.g.,
+ support for more robust encryption algorithm (CCMP: AES in Counter
+ mode with CBC-MAC) to replace TKIP and optimizations for handoff
+ (reduced number of messages in initial key handshake,
+ pre-authentication, and PMKSA caching).</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_cli.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_cli.sgml
new file mode 100644
index 000000000000..2ba1fe42236a
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -0,0 +1,360 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_cli</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_cli</refname>
+
+ <refpurpose>WPA command line client</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_cli</command>
+ <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+ <arg>-g <replaceable>path to global ctrl_interface socket</replaceable></arg>
+ <arg>-i <replaceable>ifname</replaceable></arg>
+ <arg>-hvB</arg>
+ <arg>-a <replaceable>action file</replaceable></arg>
+ <arg>-P <replaceable>pid file</replaceable></arg>
+ <arg>-G <replaceable>ping interval</replaceable></arg>
+ <arg><replaceable>command ...</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para>wpa_cli is a text-based frontend program for interacting
+ with wpa_supplicant. It is used to query current status, change
+ configuration, trigger events, and request interactive user
+ input.</para>
+
+ <para>wpa_cli can show the current authentication status, selected
+ security mode, dot11 and dot1x MIBs, etc. In addition, it can
+ configure some variables like EAPOL state machine parameters and
+ trigger events like reassociation and IEEE 802.1X
+ logoff/logon. wpa_cli provides a user interface to request
+ authentication information, like username and password, if these
+ are not included in the configuration. This can be used to
+ implement, e.g., one-time-passwords or generic token card
+ authentication where the authentication is based on a
+ challenge-response that uses an external device for generating the
+ response.</para>
+
+ <para>The control interface of wpa_supplicant can be configured to
+ allow non-root user access (ctrl_interface GROUP= parameter in the
+ configuration file). This makes it possible to run wpa_cli with a
+ normal user account.</para>
+
+ <para>wpa_cli supports two modes: interactive and command
+ line. Both modes share the same command set and the main
+ difference is in interactive mode providing access to unsolicited
+ messages (event messages, username/password requests).</para>
+
+ <para>Interactive mode is started when wpa_cli is executed without
+ including the command as a command line parameter. Commands are
+ then entered on the wpa_cli prompt. In command line mode, the same
+ commands are entered as command line arguments for wpa_cli.</para>
+ </refsect1>
+ <refsect1>
+ <title>Interactive authentication parameters request</title>
+
+ <para>When wpa_supplicant need authentication parameters, like
+ username and password, which are not present in the configuration
+ file, it sends a request message to all attached frontend programs,
+ e.g., wpa_cli in interactive mode. wpa_cli shows these requests
+ with "CTRL-REQ-&lt;type&gt;-&lt;id&gt;:&lt;text&gt;"
+ prefix. &lt;type&gt; is IDENTITY, PASSWORD, or OTP
+ (one-time-password). &lt;id&gt; is a unique identifier for the
+ current network. &lt;text&gt; is description of the request. In
+ case of OTP request, it includes the challenge from the
+ authentication server.</para>
+
+ <para>The reply to these requests can be given with
+ <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and
+ <emphasis>otp</emphasis> commands. &lt;id&gt; needs to be copied from
+ the matching request. <emphasis>password</emphasis> and
+ <emphasis>otp</emphasis> commands can be used regardless of whether
+ the request was for PASSWORD or OTP. The main difference between these
+ two commands is that values given with <emphasis>password</emphasis> are
+ remembered as long as wpa_supplicant is running whereas values given
+ with <emphasis>otp</emphasis> are used only once and then forgotten,
+ i.e., wpa_supplicant will ask frontend for a new value for every use.
+ This can be used to implement one-time-password lists and generic token
+ card -based authentication.</para>
+
+ <para>Example request for password and a matching reply:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+</programlisting></blockquote>
+
+ <para>Example request for generic token card challenge-response:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+</programlisting></blockquote>
+
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-p path</term>
+
+ <listitem><para>Change the path where control sockets should
+ be found.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-g control socket path</term>
+
+ <listitem><para>Connect to the global control socket at the
+ indicated path rather than an interface-specific control
+ socket.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i ifname</term>
+
+ <listitem><para>Specify the interface that is being
+ configured. By default, choose the first interface found with
+ a control socket in the socket path.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Help. Show a usage message.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>Show version information.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-B</term>
+ <listitem><para>Run as a daemon in the background.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a file</term>
+
+ <listitem><para>Run in daemon mode executing the action file
+ based on events from wpa_supplicant. The specified file will
+ be executed with the first argument set to interface name and
+ second to "CONNECTED" or "DISCONNECTED" depending on the event.
+ This can be used to execute networking tools required to configure
+ the interface.</para>
+
+ <para>Additionally, three environmental variables are available to
+ the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
+ contains the absolute path to the ctrl_interface socket. WPA_ID
+ contains the unique network_id identifier assigned to the active
+ network, and WPA_ID_STR contains the content of the id_str option.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-P file</term>
+
+ <listitem><para>Set the location of the PID
+ file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-G ping interval</term>
+
+ <listitem><para>Set the interval (in seconds) at which
+ wpa_cli pings the supplicant.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>command</term>
+
+ <listitem><para>Run a command. The available commands are
+ listed in the next section.</para></listitem>
+
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>Commands</title>
+ <para>The following commands are available:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>status</term>
+ <listitem>
+ <para>get current WPA/EAPOL/EAP status</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>mib</term>
+ <listitem>
+ <para>get MIB variables (dot1x, dot11)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>help</term>
+ <listitem>
+ <para>show this usage help</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>interface [ifname]</term>
+ <listitem>
+ <para>show interfaces/select interface</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>level &lt;debug level&gt;</term>
+ <listitem>
+ <para>change debug level</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>license</term>
+ <listitem>
+ <para>show full wpa_cli license</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>logoff</term>
+ <listitem>
+ <para>IEEE 802.1X EAPOL state machine logoff</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>logon</term>
+ <listitem>
+ <para>IEEE 802.1X EAPOL state machine logon</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>set</term>
+ <listitem>
+ <para>set variables (shows list of variables when run without arguments)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>pmksa</term>
+ <listitem>
+ <para>show PMKSA cache</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>reassociate</term>
+ <listitem>
+ <para>force reassociation</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>reconfigure</term>
+ <listitem>
+ <para>force wpa_supplicant to re-read its configuration file</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>preauthenticate &lt;BSSID&gt;</term>
+ <listitem>
+ <para>force preauthentication</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>identity &lt;network id&gt; &lt;identity&gt;</term>
+ <listitem>
+ <para>configure identity for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>password &lt;network id&gt; &lt;password&gt;</term>
+ <listitem>
+ <para>configure password for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>pin &lt;network id&gt; &lt;pin&gt;</term>
+ <listitem>
+ <para>configure pin for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>otp &lt;network id&gt; &lt;password&gt;</term>
+ <listitem>
+ <para>configure one-time-password for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bssid &lt;network id&gt; &lt;BSSID&gt;</term>
+ <listitem>
+ <para>set preferred BSSID for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>list_networks</term>
+ <listitem>
+ <para>list configured networks</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>terminate</term>
+ <listitem>
+ <para>terminate <command>wpa_supplicant</command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>quit</term>
+ <listitem><para>exit wpa_cli</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_gui.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_gui.sgml
new file mode 100644
index 000000000000..cb0c735e4ce7
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -0,0 +1,106 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_gui</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_gui</refname>
+
+ <refpurpose>WPA Graphical User Interface</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_gui</command>
+ <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+ <arg>-i <replaceable>ifname</replaceable></arg>
+ <arg>-m <replaceable>seconds</replaceable></arg>
+ <arg>-t</arg>
+ <arg>-q</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para>wpa_gui is a QT graphical frontend program for interacting
+ with wpa_supplicant. It is used to query current status, change
+ configuration and request interactive user input.</para>
+
+ <para>wpa_gui supports (almost) all of the interactive status and
+ configuration features of the command line client, wpa_cli. Refer
+ to the wpa_cli manpage for a comprehensive list of the
+ interactive mode features.</para>
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-p path</term>
+
+ <listitem><para>Change the path where control sockets should
+ be found.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i ifname</term>
+
+ <listitem><para>Specify the interface that is being
+ configured. By default, choose the first interface found with
+ a control socket in the socket path.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-m seconds</term>
+
+ <listitem><para>Set the update interval in seconds for the signal
+ strength meter. This value must be a positive integer, otherwise
+ meter is not enabled (default behavior).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t</term>
+
+ <listitem><para>Start program in the system tray only (if the window
+ manager supports it). By default the main status window is
+ shown.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-q</term>
+
+ <listitem><para>Run program in the quiet mode - do not display tray
+ icon pop-up messages.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_cli</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
new file mode 100644
index 000000000000..077296904f89
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -0,0 +1,77 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_passphrase</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_passphrase</refname>
+ <refpurpose>Generate a WPA PSK from an ASCII passphrase for a SSID</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_passphrase</command>
+ <arg><replaceable>ssid</replaceable></arg>
+ <arg><replaceable>passphrase</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para><command>wpa_passphrase</command> pre-computes PSK entries for
+ network configuration blocks of a
+ <filename>wpa_supplicant.conf</filename> file. An ASCII passphrase
+ and SSID are used to generate a 256-bit PSK.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <variablelist>
+ <varlistentry>
+ <term>ssid</term>
+ <listitem>
+ <para>The SSID whose passphrase should be derived.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>passphrase</term>
+ <listitem>
+ <para>The passphrase to use. If not included on the command line,
+ passphrase will be read from standard input.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_priv.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_priv.sgml
new file mode 100644
index 000000000000..0d5c94a9f776
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -0,0 +1,152 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_priv</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_priv</refname>
+
+ <refpurpose>wpa_supplicant privilege separation helper</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_priv</command>
+ <arg>-c <replaceable>ctrl path</replaceable></arg>
+ <arg>-Bdd</arg>
+ <arg>-P <replaceable>pid file</replaceable></arg>
+ <arg>driver:ifname <replaceable>[driver:ifname ...]</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para><command>wpa_priv</command> is a privilege separation helper that
+ minimizes the size of <command>wpa_supplicant</command> code that needs
+ to be run with root privileges.</para>
+
+ <para>If enabled, privileged operations are done in the wpa_priv process
+ while leaving rest of the code (e.g., EAP authentication and WPA
+ handshakes) to operate in an unprivileged process (wpa_supplicant) that
+ can be run as non-root user. Privilege separation restricts the effects
+ of potential software errors by containing the majority of the code in an
+ unprivileged process to avoid the possibility of a full system
+ compromise.</para>
+
+ <para><command>wpa_priv</command> needs to be run with network admin
+ privileges (usually, root user). It opens a UNIX domain socket for each
+ interface that is included on the command line; any other interface will
+ be off limits for <command>wpa_supplicant</command> in this kind of
+ configuration. After this, <command>wpa_supplicant</command> can be run as
+ a non-root user (e.g., all standard users on a laptop or as a special
+ non-privileged user account created just for this purpose to limit access
+ to user files even further).</para>
+ </refsect1>
+ <refsect1>
+ <title>Example configuration</title>
+
+ <para>The following steps are an example of how to configure
+ <command>wpa_priv</command> to allow users in the
+ <emphasis>wpapriv</emphasis> group to communicate with
+ <command>wpa_supplicant</command> with privilege separation:</para>
+
+ <para>Create user group (e.g., wpapriv) and assign users that
+ should be able to use wpa_supplicant into that group.</para>
+
+ <para>Create /var/run/wpa_priv directory for UNIX domain sockets and
+ control user access by setting it accessible only for the wpapriv
+ group:</para>
+
+<blockquote><programlisting>
+mkdir /var/run/wpa_priv
+chown root:wpapriv /var/run/wpa_priv
+chmod 0750 /var/run/wpa_priv
+</programlisting></blockquote>
+
+ <para>Start <command>wpa_priv</command> as root (e.g., from system
+ startup scripts) with the enabled interfaces configured on the
+ command line:</para>
+
+<blockquote><programlisting>
+wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
+</programlisting></blockquote>
+
+ <para>Run <command>wpa_supplicant</command> as non-root with a user
+ that is in the wpapriv group:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -i ath0 -c wpa_supplicant.conf
+</programlisting></blockquote>
+
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-c ctrl path</term>
+
+ <listitem><para>Specify the path to wpa_priv control directory
+ (Default: /var/run/wpa_priv/).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-B</term>
+ <listitem><para>Run as a daemon in the background.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-P file</term>
+
+ <listitem><para>Set the location of the PID
+ file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>driver:ifname [driver:ifname ...]</term>
+
+ <listitem><para>The &lt;driver&gt; string dictates which of the
+ supported <command>wpa_supplicant</command> driver backends is to be
+ used. To get a list of supported driver types see wpa_supplicant help
+ (e.g, wpa_supplicant -h). The driver backend supported by most good
+ drivers is <emphasis>wext</emphasis>.</para>
+
+ <para>The &lt;ifname&gt; string specifies which network
+ interface is to be managed by <command>wpa_supplicant</command>
+ (e.g., wlan0 or ath0).</para>
+
+ <para><command>wpa_priv</command> does not use the network interface
+ before <command>wpa_supplicant</command> is started, so it is fine to
+ include network interfaces that are not available at the time wpa_priv
+ is started. wpa_priv can control multiple interfaces with one process,
+ but it is also possible to run multiple <command>wpa_priv</command>
+ processes at the same time, if desired.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
new file mode 100644
index 000000000000..8a0314e8fb98
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
@@ -0,0 +1,243 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_supplicant.conf</refname>
+ <refpurpose>configuration file for wpa_supplicant</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Overview</title>
+
+ <para><command>wpa_supplicant</command> is configured using a text
+ file that lists all accepted networks and security policies,
+ including pre-shared keys. See the example configuration file,
+ probably in <command>/usr/share/doc/wpa_supplicant/</command>, for
+ detailed information about the configuration format and supported
+ fields.</para>
+
+ <para>All file paths in this configuration file should use full
+ (absolute, not relative to working directory) path in order to allow
+ working directory to be changed. This can happen if wpa_supplicant is
+ run in the background.</para>
+
+ <para>Changes to configuration file can be reloaded be sending
+ SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP
+ wpa_supplicant'). Similarly, reloading can be triggered with
+ the <emphasis>wpa_cli reconfigure</emphasis> command.</para>
+
+ <para>Configuration file can include one or more network blocks,
+ e.g., one for each used SSID. wpa_supplicant will automatically
+ select the best network based on the order of network blocks in
+ the configuration file, network security level (WPA/WPA2 is
+ preferred), and signal strength.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Quick Examples</title>
+
+ <orderedlist>
+ <listitem>
+
+ <para>WPA-Personal (PSK) as home network and WPA-Enterprise with
+ EAP-TLS as work network.</para>
+
+<blockquote><programlisting>
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+#
+# home network; allow all valid ciphers
+network={
+ ssid="home"
+ scan_ssid=1
+ key_mgmt=WPA-PSK
+ psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+ ssid="work"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ pairwise=CCMP TKIP
+ group=CCMP TKIP
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
+ use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
+ Aegis, Interlink RAD-Series)</para>
+
+<blockquote><programlisting>
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase1="peaplabel=0"
+ phase2="auth=MSCHAPV2"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
+ identity for the unencrypted use. Real identity is sent only
+ within an encrypted TLS tunnel.</para>
+
+
+<blockquote><programlisting>
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="user@example.com"
+ anonymous_identity="anonymous@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase2="auth=MD5"
+}
+</programlisting></blockquote>
+
+ </listitem>
+
+ <listitem>
+ <para>IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
+ (require both unicast and broadcast); use EAP-TLS for
+ authentication</para>
+
+<blockquote><programlisting>
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+ ssid="1x-test"
+ scan_ssid=1
+ key_mgmt=IEEE8021X
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ eapol_flags=3
+}
+</programlisting></blockquote>
+ </listitem>
+
+
+ <listitem>
+ <para>Catch all example that allows more or less all
+ configuration modes. The configuration options are used based
+ on what security policy is used in the selected SSID. This is
+ mostly for testing and is not recommended for normal
+ use.</para>
+
+<blockquote><programlisting>
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+ pairwise=CCMP TKIP
+ group=CCMP TKIP WEP104 WEP40
+ psk="very secret passphrase"
+ eap=TTLS PEAP TLS
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ phase1="peaplabel=0"
+ ca_cert2="/etc/cert/ca2.pem"
+ client_cert2="/etc/cer/user.pem"
+ private_key2="/etc/cer/user.prv"
+ private_key2_passwd="password"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>Authentication for wired Ethernet. This can be used with
+ <emphasis>wired</emphasis> or <emphasis>roboswitch</emphasis> interface
+ (-Dwired or -Droboswitch on command line).</para>
+
+<blockquote><programlisting>
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+ap_scan=0
+network={
+ key_mgmt=IEEE8021X
+ eap=MD5
+ identity="user"
+ password="password"
+ eapol_flags=0
+}
+</programlisting></blockquote>
+ </listitem>
+ </orderedlist>
+
+
+
+
+
+ </refsect1>
+ <refsect1>
+ <title>Certificates</title>
+
+ <para>Some EAP authentication methods require use of
+ certificates. EAP-TLS uses both server side and client
+ certificates whereas EAP-PEAP and EAP-TTLS only require the server
+ side certificate. When client certificate is used, a matching
+ private key file has to also be included in configuration. If the
+ private key uses a passphrase, this has to be configured in
+ wpa_supplicant.conf ("private_key_passwd").</para>
+
+ <para>wpa_supplicant supports X.509 certificates in PEM and DER
+ formats. User certificate and private key can be included in the
+ same file.</para>
+
+ <para>If the user certificate and private key is received in
+ PKCS#12/PFX format, they need to be converted to suitable PEM/DER
+ format for wpa_supplicant. This can be done, e.g., with following
+ commands:</para>
+<blockquote><programlisting>
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+</programlisting></blockquote>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>openssl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
new file mode 100644
index 000000000000..144654aac684
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -0,0 +1,764 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refentryinfo>
+ <date>07 August 2019</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_supplicant</refname>
+ <refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_supplicant</command>
+ <arg>-BddfhKLqqsTtuvW</arg>
+ <arg>-i<replaceable>ifname</replaceable></arg>
+ <arg>-c<replaceable>config file</replaceable></arg>
+ <arg>-D<replaceable>driver</replaceable></arg>
+ <arg>-P<replaceable>PID_file</replaceable></arg>
+ <arg>-f<replaceable>output file</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>Overview</title>
+
+ <para>
+ Wireless networks do not require physical access to the network equipment
+ in the same way as wired networks. This makes it easier for unauthorized
+ users to passively monitor a network and capture all transmitted frames.
+ In addition, unauthorized use of the network is much easier. In many cases,
+ this can happen even without user's explicit knowledge since the wireless
+ LAN adapter may have been configured to automatically join any available
+ network.
+ </para>
+
+ <para>
+ Link-layer encryption can be used to provide a layer of security for
+ wireless networks. The original wireless LAN standard, IEEE 802.11,
+ included a simple encryption mechanism, WEP. However, that proved to
+ be flawed in many areas and network protected with WEP cannot be consider
+ secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
+ can be used to improve the network security, but even that has inherited
+ security issues due to the use of WEP for encryption. Wi-Fi Protected
+ Access and IEEE 802.11i amendment to the wireless LAN standard introduce
+ a much improvement mechanism for securing wireless networks. IEEE 802.11i
+ enabled networks that are using CCMP (encryption mechanism based on strong
+ cryptographic algorithm AES) can finally be called secure used for
+ applications which require efficient protection against unauthorized
+ access.
+ </para>
+
+ <para><command>wpa_supplicant</command> is an implementation of
+ the WPA Supplicant component, i.e., the part that runs in the
+ client stations. It implements WPA key negotiation with a WPA
+ Authenticator and EAP authentication with Authentication
+ Server. In addition, it controls the roaming and IEEE 802.11
+ authentication/association of the wireless LAN driver.</para>
+
+ <para><command>wpa_supplicant</command> is designed to be a
+ "daemon" program that runs in the background and acts as the
+ backend component controlling the wireless
+ connection. <command>wpa_supplicant</command> supports separate
+ frontend programs and an example text-based frontend,
+ <command>wpa_cli</command>, is included with
+ wpa_supplicant.</para>
+
+ <para>Before wpa_supplicant can do its work, the network interface
+ must be available. That means that the physical device must be
+ present and enabled, and the driver for the device must be
+ loaded. The daemon will exit immediately if the device is not already
+ available.</para>
+
+ <para>After <command>wpa_supplicant</command> has configured the
+ network device, higher level configuration such as DHCP may
+ proceed. There are a variety of ways to integrate wpa_supplicant
+ into a machine's networking scripts, a few of which are described
+ in sections below.</para>
+
+ <para>The following steps are used when associating with an AP
+ using WPA:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><command>wpa_supplicant</command> requests the kernel
+ driver to scan neighboring BSSes</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> selects a BSS based on
+ its configuration</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> requests the kernel
+ driver to associate with the chosen BSS</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-EAP: integrated IEEE 802.1X Supplicant
+ completes EAP authentication with the
+ authentication server (proxied by the Authenticator in the
+ AP)</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-EAP: master key is received from the IEEE 802.1X
+ Supplicant</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK
+ as the master session key</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> completes WPA 4-Way
+ Handshake and Group Key Handshake with the Authenticator
+ (AP)</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> configures encryption
+ keys for unicast and broadcast</para>
+ </listitem>
+
+ <listitem>
+ <para>normal data packets can be transmitted and received</para>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Supported Features</title>
+ <para>Supported WPA/IEEE 802.11i features:</para>
+ <itemizedlist>
+ <listitem>
+ <para>WPA-PSK ("WPA-Personal")</para>
+ </listitem>
+
+ <listitem>
+ <para>WPA with EAP (e.g., with RADIUS authentication server)
+ ("WPA-Enterprise") Following authentication methods are
+ supported with an integrate IEEE 802.1X Supplicant:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>EAP-TLS</para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+
+ <listitem>
+ <para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-MD5-Challenge</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-GTC</para>
+ </listitem>
+
+ <listitem><para>EAP-TTLS/EAP-OTP</para></listitem>
+
+ <listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-TTLS/EAP-TLS</para></listitem>
+
+ <listitem><para>EAP-TTLS/MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-TTLS/MSCHAP</para></listitem>
+
+ <listitem><para>EAP-TTLS/PAP</para></listitem>
+
+ <listitem><para>EAP-TTLS/CHAP</para></listitem>
+
+ <listitem><para>EAP-SIM</para></listitem>
+
+ <listitem><para>EAP-AKA</para></listitem>
+
+ <listitem><para>EAP-PSK</para></listitem>
+
+ <listitem><para>EAP-PAX</para></listitem>
+
+ <listitem><para>LEAP (note: requires special support from
+ the driver for IEEE 802.11 authentication)</para></listitem>
+
+ <listitem><para>(following methods are supported, but since
+ they do not generate keying material, they cannot be used
+ with WPA or IEEE 802.1X WEP keying)</para></listitem>
+
+ <listitem><para>EAP-MD5-Challenge </para></listitem>
+
+ <listitem><para>EAP-MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-GTC</para></listitem>
+
+ <listitem><para>EAP-OTP</para></listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>key management for CCMP, TKIP, WEP104, WEP40</para>
+ </listitem>
+
+ <listitem>
+ <para>RSN/WPA2 (IEEE 802.11i)</para>
+ <itemizedlist>
+ <listitem>
+ <para>pre-authentication</para>
+ </listitem>
+
+ <listitem>
+ <para>PMKSA caching</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Available Drivers</title>
+ <para>A summary of available driver backends is below. Support for each
+ of the driver backends is chosen at wpa_supplicant compile time. For a
+ list of supported driver backends that may be used with the -D option on
+ your system, refer to the help output of wpa_supplicant
+ (<emphasis>wpa_supplicant -h</emphasis>).</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>nl80211</term>
+ <listitem>
+ <para>Uses the modern Linux nl80211/cfg80211 netlink-based
+ interface (most new drivers).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>wext</term>
+ <listitem>
+ <para>Uses the legacy Linux wireless extensions ioctl-based
+ interface (older hardware/drivers).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>wired</term>
+ <listitem>
+ <para>wpa_supplicant wired Ethernet driver</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>roboswitch</term>
+ <listitem>
+ <para>wpa_supplicant Broadcom switch driver</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bsd</term>
+ <listitem>
+ <para>BSD 802.11 support (Atheros, etc.).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ndis</term>
+ <listitem>
+ <para>Windows NDIS driver.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Command Line Options</title>
+ <para>Most command line options have global scope. Some are given per
+ interface, and are only valid if at least one <option>-i</option> option
+ is specified, otherwise they're ignored. Option groups for different
+ interfaces must be separated by <option>-N</option> option.</para>
+ <variablelist>
+ <varlistentry>
+ <term>-b br_ifname</term>
+ <listitem>
+ <para>Optional bridge interface name. (Per interface)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-B</term>
+ <listitem>
+ <para>Run daemon in the background.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-c filename</term>
+ <listitem>
+ <para>Path to configuration file. (Per interface)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-C ctrl_interface</term>
+ <listitem>
+ <para>Path to ctrl_interface socket (Per interface. Only used if
+ <option>-c</option> is not).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i ifname</term>
+ <listitem>
+ <para>Interface to listen on. Multiple instances of this option can
+ be present, one per interface, separated by <option>-N</option>
+ option (see below).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-d</term>
+ <listitem>
+ <para>Increase debugging verbosity (<option>-dd</option> even
+ more).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-D driver</term>
+ <listitem>
+ <para>Driver to use (can be multiple drivers: nl80211,wext).
+ (Per interface, see the available options below.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-e entropy file</term>
+ <listitem>
+ <para>File for <command>wpa_supplicant</command> to use to
+ maintain its internal entropy store in over restarts.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-f output file</term>
+ <listitem>
+ <para>Log output to specified file instead of stdout. (This
+ is only available if <command>wpa_supplicant</command> was
+ built with the <literal>CONFIG_DEBUG_FILE</literal>
+ option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-g global ctrl_interface</term>
+ <listitem>
+ <para>Path to global ctrl_interface socket. If specified, interface
+ definitions may be omitted.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-K</term>
+ <listitem>
+ <para>Include keys (passwords, etc.) in debug output.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem>
+ <para>Help. Show a usage message.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-L</term>
+ <listitem>
+ <para>Show license (BSD).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o override driver</term>
+ <listitem>
+ <para>Override the driver parameter for new
+ interfaces.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O override ctrl_interface</term>
+ <listitem>
+ <para>Override the ctrl_interface parameter for new
+ interfaces.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-p</term>
+ <listitem>
+ <para>Driver parameters. (Per interface)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-P PID_file</term>
+ <listitem>
+ <para>Path to PID file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-q</term>
+ <listitem>
+ <para>Decrease debugging verbosity (<option>-qq</option> even
+ less).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s</term>
+ <listitem>
+ <para>Log output to syslog instead of stdout. (This is only
+ available if <command>wpa_supplicant</command> was built
+ with the <literal>CONFIG_DEBUG_SYSLOG</literal>
+ option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-T</term>
+ <listitem>
+ <para>Log output to Linux tracing in addition to any other
+ destinations. (This is only available
+ if <command>wpa_supplicant</command> was built with
+ the <literal>CONFIG_DEBUG_LINUX_TRACING</literal>
+ option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t</term>
+ <listitem>
+ <para>Include timestamp in debug messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-u</term>
+ <listitem>
+ <para>Enable DBus control interface. If enabled, interface
+ definitions may be omitted. (This is only available
+ if <command>wpa_supplicant</command> was built with
+ the <literal>CONFIG_CTRL_IFACE_DBUS_NEW</literal> option.)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem>
+ <para>Show version.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-W</term>
+ <listitem>
+ <para>Wait for a control interface monitor before starting.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-N</term>
+ <listitem>
+ <para>Start describing new interface.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>In most common cases, <command>wpa_supplicant</command> is
+ started with:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
+ <para>This makes the process fork into background.</para>
+
+ <para>The easiest way to debug problems, and to get debug log for
+ bug reports, is to start <command>wpa_supplicant</command> on
+ foreground with debugging enabled:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+</programlisting></blockquote>
+
+ <para>If the specific driver wrapper is not known beforehand, it is
+ possible to specify multiple comma separated driver wrappers on the command
+ line. <command>wpa_supplicant</command> will use the first driver
+ wrapper that is able to initialize the interface.</para>
+
+<blockquote><programlisting>
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
+ <para><command>wpa_supplicant</command> can control multiple
+ interfaces (radios) either by running one process for each
+ interface separately or by running just one process and list of
+ options at command line. Each interface is separated with -N
+ argument. As an example, following command would start
+ wpa_supplicant for two interfaces:</para>
+
+<blockquote><programlisting>
+wpa_supplicant \
+ -c wpa1.conf -i wlan0 -D nl80211 -N \
+ -c wpa2.conf -i ath0 -D wext
+</programlisting></blockquote>
+ </refsect1>
+
+ <refsect1>
+ <title>OS Requirements</title>
+ <para>Current hardware/software requirements:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Linux kernel 2.6.30 or higher with
+ nl80211/cfg80211 support</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux kernel 2.4.x or higher with Linux Wireless
+ Extensions v15 or newer</para>
+ </listitem>
+
+ <listitem>
+ <para>FreeBSD 6-CURRENT</para>
+ </listitem>
+
+ <listitem>
+ <para>Microsoft Windows with WinPcap (at least WinXP, may work
+ with other versions)</para>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Supported Drivers</title>
+ <variablelist>
+ <varlistentry>
+ <term>Linux nl80211/cfg80211</term>
+ <listitem>
+ <para>This is the preferred driver for Linux.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Linux wireless extensions</term>
+ <listitem>
+ <para>In theory, any driver that supports Linux wireless
+ extensions can be used with IEEE 802.1X (i.e., not WPA) when
+ using ap_scan=0 option in configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Wired Ethernet drivers</term>
+ <listitem>
+ <para>Use ap_scan=0.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BSD net80211 layer (e.g., Atheros driver)</term>
+ <listitem>
+ <para>At the moment, this is for FreeBSD 6-CURRENT branch.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Windows NDIS</term>
+ <listitem>
+ <para>The current Windows port requires WinPcap
+ (http://winpcap.polito.it/). See README-Windows.txt for more
+ information.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ <para>wpa_supplicant was designed to be portable for different
+ drivers and operating systems. Hopefully, support for more wlan
+ cards and OSes will be added in the future. See developer.txt for
+ more information about the design of wpa_supplicant and porting to
+ other drivers. One main goal is to add full WPA/WPA2 support to
+ Linux wireless extensions to allow new drivers to be supported
+ without having to implement new driver-specific interface code in
+ wpa_supplicant.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Architecture</title> <para>The
+ <command>wpa_supplicant</command> system consists of the following
+ components:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>wpa_supplicant.conf</filename> </term>
+ <listitem>
+ <para>the configuration file describing all networks that the
+ user wants the computer to connect to. </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_supplicant</command></term>
+ <listitem><para>the program that directly interacts with the
+ network interface. </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_cli</command></term> <listitem><para> the
+ client program that provides a high-level interface to the
+ functionality of the daemon. </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_passphrase</command></term>
+ <listitem><para>a utility needed to construct
+ <filename>wpa_supplicant.conf</filename> files that include
+ encrypted passwords.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Quick Start</title>
+
+ <para>First, make a configuration file, e.g.
+ <filename>/etc/wpa_supplicant.conf</filename>, that describes the networks
+ you are interested in. See <citerefentry>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ for details.</para>
+
+ <para>Once the configuration is ready, you can test whether the
+ configuration works by running <command>wpa_supplicant</command>
+ with following command to start it on foreground with debugging
+ enabled:</para>
+
+ <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+ </programlisting></blockquote>
+
+ <para>Assuming everything goes fine, you can start using following
+ command to start <command>wpa_supplicant</command> on background
+ without debugging:</para>
+
+ <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+ </programlisting></blockquote>
+
+ <para>Please note that if you included more than one driver
+ interface in the build time configuration (.config), you may need
+ to specify which interface to use by including -D&lt;driver
+ name&gt; option on the command line.</para>
+
+ <!-- XXX at this point, the page could include a little script
+ based on wpa_cli to wait for a connection and then run
+ dhclient -->
+
+ </refsect1>
+
+ <refsect1>
+ <title>Interface to pcmcia-cs/cardmrg</title>
+
+ <para>For example, following small changes to pcmcia-cs scripts
+ can be used to enable WPA support:</para>
+
+ <para>Add MODE="Managed" and WPA="y" to the network scheme in
+ <filename>/etc/pcmcia/wireless.opts</filename>.</para>
+
+ <para>Add the following block to the end of <emphasis>start</emphasis>
+ action handler in <filename>/etc/pcmcia/wireless</filename>:</para>
+
+ <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE
+fi
+ </programlisting></blockquote>
+
+
+ <para>Add the following block to the end of <emphasis>stop</emphasis>
+ action handler (may need to be separated from other actions) in
+ <filename>/etc/pcmcia/wireless</filename>:</para>
+
+ <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ killall wpa_supplicant
+fi
+ </programlisting></blockquote>
+
+ <para>This will make <command>cardmgr</command> start
+ <command>wpa_supplicant</command> when the card is plugged
+ in.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_background</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_cli</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_passphrase</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2019,
+ Jouni Malinen <email>j@w1.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.c b/contrib/wpa/wpa_supplicant/dpp_supplicant.c
index 1f65658eff76..40ef8aeb510f 100644
--- a/contrib/wpa/wpa_supplicant/dpp_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.c
@@ -1,7 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/ip_addr.h"
+#include "utils/base64.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
@@ -31,6 +32,7 @@
static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
unsigned int freq);
static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
@@ -45,6 +47,13 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
const u8 *src, const u8 *bssid,
const u8 *data, size_t data_len,
enum offchannel_send_action_result result);
+#ifdef CONFIG_DPP2
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth);
+#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -84,10 +93,99 @@ int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
500, wpas_dpp_tx_status, 0);
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
+ return bi->id;
+}
+
+
+/**
+ * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
+ if (!bi)
+ return -1;
+
return bi->id;
}
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+ own_bi->nfc_negotiated = 1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+ own_bi->nfc_negotiated = 1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -148,6 +246,8 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->suitable_network = 0;
+ wpa_s->no_suitable_network = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
@@ -157,6 +257,172 @@ static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ unsigned int wait_time)
+{
+ struct os_reltime now, res;
+ unsigned int remaining;
+
+ if (!wpa_s->dpp_listen_freq)
+ return;
+
+ os_get_reltime(&now);
+ if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) {
+ os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res);
+ remaining = res.sec * 1000 + res.usec / 1000;
+ } else {
+ remaining = 0;
+ }
+ if (wpa_s->dpp_listen_freq == freq && remaining > wait_time)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms",
+ wpa_s->dpp_listen_freq, remaining, freq, wait_time);
+ wpas_dpp_listen_stop(wpa_s);
+
+ /* TODO: Restart listen in some cases after TX? */
+}
+
+
+static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error result;
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connection timeout - report Connection Status Result");
+ if (wpa_s->suitable_network)
+ result = DPP_STATUS_AUTH_FAILURE;
+ else if (wpa_s->no_suitable_network)
+ result = DPP_STATUS_NO_AP;
+ else
+ result = 255; /* What to report here for unexpected state? */
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpas_abort_ongoing_scan(wpa_s);
+ wpas_dpp_send_conn_status_result(wpa_s, result);
+}
+
+
+static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
+{
+ char *str, *end, *pos;
+ size_t len;
+ unsigned int i;
+ u8 last_op_class = 0;
+ int res;
+
+ if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
+ return NULL;
+
+ len = wpa_s->num_last_scan_freqs * 8;
+ str = os_zalloc(len);
+ if (!str)
+ return NULL;
+ end = str + len;
+ pos = str;
+
+ for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+
+ mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
+ 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ continue;
+ if (op_class == last_op_class)
+ res = os_snprintf(pos, end - pos, ",%d", channel);
+ else
+ res = os_snprintf(pos, end - pos, "%s%d/%d",
+ pos == str ? "" : ",",
+ op_class, channel);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ last_op_class = op_class;
+ }
+
+ if (pos == str) {
+ os_free(str);
+ str = NULL;
+ }
+ return str;
+}
+
+
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result)
+{
+ struct wpabuf *msg;
+ const char *channel_list = NULL;
+ char *channel_list_buf = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+ auth->conn_status_requested = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
+ result);
+
+ if (result == DPP_STATUS_NO_AP) {
+ channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
+ channel_list = channel_list_buf;
+ }
+
+ msg = dpp_build_conn_status_result(auth, result,
+ ssid ? ssid->ssid :
+ wpa_s->dpp_last_ssid,
+ ssid ? ssid->ssid_len :
+ wpa_s->dpp_last_ssid_len,
+ channel_list);
+ os_free(channel_list_buf);
+ if (!msg) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_CONNECTION_STATUS_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->remove_on_tx_status = 1;
+
+ return;
+}
+
+
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (auth && auth->conn_status_requested)
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -182,22 +448,40 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
+ auth->connect_on_tx_status = 0;
wpa_printf(MSG_DEBUG,
"DPP: Try to connect after completed configuration result");
wpas_dpp_try_to_connect(wpa_s);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
+ if (auth->conn_status_requested) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start 15 second timeout for reporting connection status result");
+ eloop_cancel_timeout(
+ wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 15, 0, wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ } else {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
return;
}
#endif /* CONFIG_DPP2 */
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
- "DPP: Terminate authentication exchange due to an earlier error");
+ "DPP: Terminate authentication exchange due to a request to do so on TX status");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -224,6 +508,17 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
}
}
+ if (auth->waiting_auth_conf &&
+ auth->auth_resp_status == DPP_STATUS_OK) {
+ /* Make sure we do not get stuck waiting for Auth Confirm
+ * indefinitely after successfully transmitted Auth Response to
+ * allow new authentication exchanges to be started. */
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
+ eloop_register_timeout(1, 0, wpas_dpp_auth_conf_wait_timeout,
+ wpa_s, NULL);
+ }
+
if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
/* Allow timeout handling to stop iteration if no response is
@@ -312,6 +607,23 @@ static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void wpas_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_auth_conf)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL "No Auth Confirm received");
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
struct dpp_authentication *auth)
{
@@ -397,7 +709,9 @@ static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
freq = auth->freq[auth->freq_idx++];
auth->curr_freq = freq;
- if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ if (!is_zero_ether_addr(auth->peer_mac_addr))
+ dst = auth->peer_mac_addr;
+ else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
dst = broadcast;
else
dst = auth->peer_bi->mac_addr;
@@ -511,7 +825,14 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
pos = os_strstr(cmd, " netrole=");
if (pos) {
pos += 9;
- wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ if (os_strncmp(pos, "ap", 2) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strncmp(pos, "configurator", 12) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ } else {
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
}
pos = os_strstr(cmd, " neg_freq=");
@@ -521,19 +842,25 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
if (!tcp && wpa_s->dpp_auth) {
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s,
+ NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
}
- auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq,
- wpa_s->hw.modes, wpa_s->hw.num_modes);
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
if (!auth)
goto fail;
wpas_dpp_set_testing_options(wpa_s, auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) {
+ if (dpp_set_configurator(auth, cmd) < 0) {
dpp_auth_deinit(auth);
goto fail;
}
@@ -545,7 +872,9 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
#ifdef CONFIG_DPP2
if (tcp)
- return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
+ wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+ wpa_s, wpa_s, wpas_dpp_process_conf_obj);
#endif /* CONFIG_DPP2 */
wpa_s->dpp_auth = auth;
@@ -614,6 +943,7 @@ static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
}
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = lwork->freq;
+ wpa_drv_dpp_listen(wpa_s, true);
}
@@ -663,7 +993,12 @@ int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
- wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+ if (os_strstr(cmd, " netrole=ap"))
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strstr(cmd, " netrole=configurator"))
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
freq);
@@ -683,11 +1018,30 @@ void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
wpa_s->dpp_listen_freq);
wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_drv_dpp_listen(wpa_s, false);
wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
}
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, unsigned int duration)
+{
+ if (wpa_s->dpp_listen_freq != freq)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Remain-on-channel started for listen on %u MHz for %u ms",
+ freq, duration);
+ os_get_reltime(&wpa_s->dpp_listen_end);
+ wpa_s->dpp_listen_end.usec += duration * 1000;
+ while (wpa_s->dpp_listen_end.usec >= 1000000) {
+ wpa_s->dpp_listen_end.sec++;
+ wpa_s->dpp_listen_end.usec -= 1000000;
+ }
+}
+
+
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
@@ -729,6 +1083,10 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -767,7 +1125,8 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_s->dpp_gas_client = 0;
wpa_s->dpp_auth_ok_on_ack = 0;
- wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
+ wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
+ wpa_s->dpp_allowed_roles,
wpa_s->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!wpa_s->dpp_auth) {
@@ -775,7 +1134,7 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+ if (dpp_set_configurator(wpa_s->dpp_auth,
wpa_s->dpp_configurator_params) < 0) {
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -809,19 +1168,21 @@ static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
- if (auth->akm == DPP_AKM_SAE) {
+ if (conf->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
res = wpa_drv_get_capa(wpa_s, &capa);
if (res == 0 &&
- !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !(capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
wpa_printf(MSG_DEBUG,
"DPP: SAE not supported by the driver");
@@ -841,27 +1202,38 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_DPP;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ if (conf->connector) {
+ if (dpp_akm_dpp(conf->akm)) {
+ ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ }
+ ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
+ }
+
+ if (conf->pp_key) {
+ ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
+ if (!ssid->dpp_pp_key)
+ goto fail;
+ os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
}
if (auth->net_access_key) {
@@ -876,29 +1248,128 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector || dpp_akm_psk(auth->akm) ||
- dpp_akm_sae(auth->akm)) {
- if (!auth->connector)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector || !dpp_akm_dpp(conf->akm))
ssid->key_mgmt = 0;
- if (dpp_akm_psk(auth->akm))
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (dpp_akm_sae(auth->akm))
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
+#if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
+ if (conf->akm == DPP_AKM_DOT1X) {
+ int i;
+ char name[100], blobname[128];
+ struct wpa_config_blob *blob;
+
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SHA256;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+
+ if (conf->cacert) {
+ /* caCert is DER-encoded X.509v3 certificate for the
+ * server certificate if that is different from the
+ * trust root included in certBag. */
+ /* TODO: ssid->eap.cert.ca_cert */
+ }
+
+ if (conf->certs) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-certs-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(conf->certs);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(conf->certs),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
+ name);
+ ssid->eap.cert.client_cert = os_strdup(blobname);
+ if (!ssid->eap.cert.client_cert)
+ goto fail;
+
+ /* TODO: ssid->eap.identity from own certificate */
+ if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
+ 0) < 0)
+ goto fail;
+ }
+
+ if (auth->priv_key) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-key-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(auth->priv_key);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(auth->priv_key),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
+ name);
+ ssid->eap.cert.private_key = os_strdup(blobname);
+ if (!ssid->eap.cert.private_key)
+ goto fail;
+ }
+
+ if (conf->server_name) {
+ ssid->eap.cert.domain_suffix_match =
+ os_strdup(conf->server_name);
+ if (!ssid->eap.cert.domain_suffix_match)
+ goto fail;
+ }
+
+ /* TODO: Use entCreds::eapMethods */
+ if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 && IEEE8021X_EAPOL */
+
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -908,14 +1379,15 @@ fail:
static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
return -1;
@@ -929,54 +1401,109 @@ static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+#ifdef CONFIG_DPP2
+ if (auth->reconfig && wpa_s->dpp_reconfig_ssid &&
+ wpa_config_get_network(wpa_s->conf, wpa_s->dpp_reconfig_ssid_id) ==
+ wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Remove reconfigured network profile");
+ wpas_notify_network_removed(wpa_s, wpa_s->dpp_reconfig_ssid);
+ wpa_config_remove_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id);
+ wpa_s->dpp_reconfig_ssid = NULL;
+ wpa_s->dpp_reconfig_ssid_id = -1;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_s->conf->dpp_config_processing < 2)
- return 0;
+ return;
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2) {
wpa_printf(MSG_DEBUG,
"DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
auth->connect_on_tx_status = 1;
- return 0;
+ return;
}
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
- return 0;
}
static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
+ dpp_akm_str(conf->akm));
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->ssid_charset)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
+ conf->ssid_charset);
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
+ }
+ if (conf->passphrase[0]) {
+ char hex[64 * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex),
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
+ hex);
+ } else if (conf->psk_set) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
+ hex);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
}
}
+ if (conf->pp_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
if (auth->net_access_key) {
char *hex;
size_t hexlen;
@@ -999,8 +1526,86 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+#ifdef CONFIG_DPP2
+ if (conf->certbag) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
+ wpabuf_len(conf->certbag), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->cacert) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
+ wpabuf_len(conf->cacert), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->server_name)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
+ conf->server_name);
+#endif /* CONFIG_DPP2 */
+
+ return wpas_dpp_process_config(wpa_s, auth, conf);
+}
+
+
+static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_s->dpp_conf_backup_received = true;
+
+ while (key) {
+ res = dpp_configurator_from_backup(wpa_s->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
+#ifdef CONFIG_DPP2
+static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
+ wpa_s->conf->dpp_name : "Test");
+ if (!auth->csr) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpas_dpp_start_gas_client(wpa_s);
}
+#endif /* CONFIG_DPP2 */
static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
@@ -1013,10 +1618,12 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
- if (!auth || !auth->auth_success) {
+ if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
+ os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
@@ -1045,13 +1652,29 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP2
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
- res = wpas_dpp_handle_config_obj(wpa_s, auth);
- if (res < 0)
+ wpa_s->dpp_conf_backup_received = false;
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
+ if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
goto fail;
status = DPP_STATUS_OK;
@@ -1086,6 +1709,9 @@ fail:
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
+ if (wpa_s->conf->dpp_config_processing < 2 ||
+ wpa_s->dpp_conf_backup_received)
+ auth->remove_on_tx_status = 1;
return;
}
fail2:
@@ -1099,27 +1725,19 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
+ int *supp_op_classes;
wpa_s->dpp_gas_client = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- wpa_s->dpp_netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- buf = dpp_build_conf_req(auth, json);
+ supp_op_classes = wpas_supp_op_classes(wpa_s);
+ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
+ wpa_s->dpp_netrole,
+ wpa_s->conf->dpp_mud_url,
+ supp_op_classes);
+ os_free(supp_op_classes);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -1130,7 +1748,7 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
- 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
+ 1, 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
@@ -1242,6 +1860,8 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
+
if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
return;
@@ -1270,6 +1890,24 @@ static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
}
+static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conn_status_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -1280,9 +1918,22 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
MAC2STR(src));
if (!auth || !auth->waiting_conf_result) {
- wpa_printf(MSG_DEBUG,
- "DPP: No DPP Configuration waiting for result - drop");
- return;
+ if (auth &&
+ os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) == 0 &&
+ gas_server_response_sent(wpa_s->gas_server,
+ auth->gas_server_ctx)) {
+ /* This could happen if the TX status event gets delayed
+ * long enough for the Enrollee to have time to send
+ * the next frame before the TX status gets processed
+ * locally. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS response was sent but TX status not yet received - assume it was ACKed since the Enrollee sent the next frame in the sequence");
+ auth->waiting_conf_result = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
}
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
@@ -1293,6 +1944,23 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(16, 0,
+ wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
+ auth->curr_freq);
+ return;
+ }
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (status == DPP_STATUS_OK)
@@ -1305,12 +1973,373 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
}
+static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+}
+
+
static int wpas_dpp_process_conf_obj(void *ctx,
struct dpp_authentication *auth)
{
struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
+
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
+
+ return res;
+}
+
+
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (bi == wpa_s->dpp_chirp_bi)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+ dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
+ freq, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
+ if (!auth)
+ return;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ /* The source address of the Presence Announcement frame overrides any
+ * MAC address information from the bootstrapping information. */
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+
+ wpa_s->dpp_auth = auth;
+ if (wpas_dpp_auth_init_next(wpa_s) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
+
+static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
- return wpas_dpp_handle_config_obj(wpa_s, auth);
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void
+wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
+ struct dpp_configurator *conf;
+ struct dpp_authentication *auth;
+ unsigned int wait_time, max_wait_time;
+ u16 group;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
+ MAC2STR(src));
+
+ csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+ &csign_hash_len);
+ if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Configurator C-sign key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+ csign_hash, csign_hash_len);
+ conf = dpp_configurator_find_kid(wpa_s->dpp, csign_hash);
+ if (!conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching Configurator information found");
+ return;
+ }
+
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
+ if (!auth)
+ return;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_s->dpp_auth = auth;
+
+ wpa_s->dpp_in_response_listen = 0;
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ wait_time = wpa_s->max_remain_on_chan;
+ max_wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+ wait_time -= 10;
+
+ wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->reconfig_req_msg),
+ wpabuf_len(auth->reconfig_req_msg),
+ wait_time, wpas_dpp_tx_status, 0) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpa_ssid *ssid;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
+ MACSTR, MAC2STR(src));
+
+ if (!wpa_s->dpp)
+ return;
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
+ return;
+ }
+ if (!wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - not requested");
+ return;
+ }
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->dpp_reconfig_ssid &&
+ ssid->id == wpa_s->dpp_reconfig_ssid_id)
+ break;
+ }
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
+ return;
+ }
+
+ auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ ssid->dpp_csign, ssid->dpp_csign_len,
+ freq, hdr, buf, len);
+ if (!auth)
+ return;
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_s->dpp_auth = auth;
+
+ wpas_dpp_chirp_stop(wpa_s);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_RESP);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->reconfig_resp_msg),
+ wpabuf_len(auth->reconfig_resp_msg),
+ 500, wpas_dpp_tx_status, 0) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *conf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || !auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+ if (!conf)
+ return;
+
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, wpa_s, NULL);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
+ if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(conf), wpabuf_len(conf),
+ 500, wpas_dpp_tx_status, 0) < 0) {
+ wpabuf_free(conf);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+ wpabuf_free(conf);
+
+ wpas_dpp_start_gas_server(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0)
+ return;
+
+ wpas_dpp_start_gas_client(wpa_s);
}
#endif /* CONFIG_DPP2 */
@@ -1323,6 +2352,11 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid;
const u8 *connector, *trans_id, *status;
u16 connector_len, trans_id_len, status_len;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+ u8 peer_version = 1;
struct dpp_introduction intro;
struct rsn_pmksa_cache_entry *entry;
struct os_time now;
@@ -1383,6 +2417,9 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
status[0]);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" status=%u", MAC2STR(src), status[0]);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, status[0]);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1406,6 +2443,9 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
"DPP: Network Introduction protocol resulted in failure");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" fail=peer_connector_validation_failed", MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1417,6 +2457,13 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
entry->pmk_len = intro.pmk_len;
entry->akmp = WPA_KEY_MGMT_DPP;
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version && version_len >= 1)
+ peer_version = version[0];
+ entry->dpp_pfs = peer_version >= 2;
+#endif /* CONFIG_DPP2 */
if (expiry) {
os_get_time(&now);
seconds = expiry - now.sec;
@@ -1430,7 +2477,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
- " status=%u", MAC2STR(src), status[0]);
+ " status=%u version=%u", MAC2STR(src), status[0], peer_version);
wpa_printf(MSG_DEBUG,
"DPP: Try connection again after successful network introduction");
@@ -1771,6 +2818,7 @@ wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Authentication initialization failed");
+ offchannel_send_action_done(wpa_s);
return;
}
}
@@ -1848,6 +2896,26 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
case DPP_PA_CONFIGURATION_RESULT:
wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
+ break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_ANNOUNCEMENT:
+ wpas_dpp_rx_reconfig_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_REQ:
+ wpas_dpp_rx_reconfig_auth_req(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_CONF:
+ wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1869,8 +2937,8 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
static struct wpabuf *
-wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
- size_t query_len)
+wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len, u16 *comeback_delay)
{
struct wpa_supplicant *wpa_s = ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
@@ -1878,7 +2946,7 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
MAC2STR(sa));
- if (!auth || !auth->auth_success ||
+ if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
@@ -1901,9 +2969,20 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
+
+#ifdef CONFIG_DPP2
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ auth->cert_resp_ctx = resp_ctx;
+ *comeback_delay = 500;
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
+
if (!resp)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
auth->conf_resp = resp;
+ auth->gas_server_ctx = resp_ctx;
return resp;
}
@@ -1926,13 +3005,23 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->waiting_csr && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ wpabuf_free(resp);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
if (ok && auth->peer_version >= 2 &&
- auth->conf_resp_status == DPP_STATUS_OK) {
+ auth->conf_resp_status == DPP_STATUS_OK &&
+ !auth->waiting_conf_result) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
auth->waiting_conf_result = 1;
auth->conf_resp = NULL;
@@ -1963,15 +3052,18 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
wpas_dpp_set_testing_options(wpa_s, auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0)
- ret = wpas_dpp_handle_config_obj(wpa_s, auth);
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
@@ -2009,6 +3101,7 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
unsigned int wait_time;
const u8 *rsn;
struct wpa_ie_data ied;
+ size_t len;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
return 0; /* Not using DPP AKM - continue */
@@ -2042,8 +3135,11 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
"DPP: Starting network introduction protocol to derive PMKSA for "
MACSTR, MAC2STR(bss->bssid));
- msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
- 5 + 4 + os_strlen(ssid->dpp_connector));
+ len = 5 + 4 + os_strlen(ssid->dpp_connector);
+#ifdef CONFIG_DPP2
+ len += 5;
+#endif /* CONFIG_DPP2 */
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ, len);
if (!msg)
return -1;
@@ -2098,6 +3194,15 @@ skip_trans_id:
skip_connector:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1) {
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
/* TODO: Timeout on AP response */
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
@@ -2238,6 +3343,8 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+ offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
dpp_pkex_free(wpa_s->dpp_pkex);
@@ -2264,10 +3371,9 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s)
return -1;
os_memset(&config, 0, sizeof(config));
- config.msg_ctx = wpa_s;
config.cb_ctx = wpa_s;
#ifdef CONFIG_DPP2
- config.process_conf_obj = wpas_dpp_process_conf_obj;
+ config.remove_bi = wpas_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
wpa_s->dpp = dpp_global_init(&config);
return wpa_s->dpp ? 0 : -1;
@@ -2287,15 +3393,24 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->dpp)
return;
- dpp_global_clear(wpa_s->dpp);
eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
+ wpas_dpp_chirp_stop(wpa_s);
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -2304,24 +3419,531 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
+ dpp_global_clear(wpa_s->dpp);
}
#ifdef CONFIG_DPP2
+
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
{
struct dpp_controller_config config;
const char *pos;
os_memset(&config, 0, sizeof(config));
+ config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_STA;
+ config.msg_ctx = wpa_s;
+ config.cb_ctx = wpa_s;
+ config.process_conf_obj = wpas_dpp_process_conf_obj;
if (cmd) {
pos = os_strstr(cmd, " tcp_port=");
if (pos) {
pos += 10;
config.tcp_port = atoi(pos);
}
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ config.allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ return -1;
+ }
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
}
config.configurator_params = wpa_s->dpp_configurator_params;
return dpp_controller_start(wpa_s->dpp, &config);
}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+ wpa_s->dpp_chirp_freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+ if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *msg, *announce = NULL;
+ int type;
+
+ msg = wpa_s->dpp_presence_announcement;
+ type = DPP_PA_PRESENCE_ANNOUNCEMENT;
+ if (!msg) {
+ struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
+
+ if (ssid && wpa_s->dpp_reconfig_id &&
+ wpa_config_get_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id) ==
+ ssid) {
+ announce = dpp_build_reconfig_announcement(
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ wpa_s->dpp_reconfig_id);
+ msg = announce;
+ }
+ if (!msg)
+ return;
+ type = DPP_PA_RECONFIG_ANNOUNCEMENT;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), wpa_s->dpp_chirp_freq, type);
+ if (offchannel_send_action(
+ wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 2000, wpas_dpp_chirp_tx_status, 0) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+ struct wpa_bss *bss;
+ bool chan6 = wpa_s->hw.modes == NULL;
+
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
+ return;
+
+ wpa_s->dpp_chirp_scan_done = 1;
+
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ if (bi) {
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+ bi->freq[i]);
+ }
+
+ /* Preferred chirping channels */
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211G, false);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ chan->freq != 2437)
+ continue;
+ chan6 = true;
+ break;
+ }
+ }
+ if (chan6)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, false);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, false);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!wpa_s->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i;
+
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+
+ if (wpa_s->dpp_chirp_freq == 0) {
+ if (wpa_s->dpp_chirp_round % 4 == 0 &&
+ !wpa_s->dpp_chirp_scan_done) {
+ if (wpas_scan_scheduled(wpa_s)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Deferring chirp scan because another scan is planned already");
+ if (eloop_register_timeout(1, 0,
+ wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ return;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->scan_res_handler =
+ wpas_dpp_chirp_scan_res_handler;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+ wpa_s->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ wpa_s->dpp_chirp_round);
+ } else {
+ for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+ if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+ break;
+ if (!wpa_s->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ wpa_s->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (wpa_s->dpp_chirp_freqs[i]) {
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+ } else {
+ wpa_s->dpp_chirp_iter--;
+ if (wpa_s->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ if (wpa_s->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ wpa_s->dpp_chirp_listen);
+ wpas_dpp_listen_start(wpa_s,
+ wpa_s->dpp_chirp_listen);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (listen_freq <= 0)
+ return -1;
+ }
+
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_chirp_bi = bi;
+ wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!wpa_s->dpp_presence_announcement)
+ return -1;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->dpp_presence_announcement ||
+ wpa_s->dpp_reconfig_ssid) {
+ offchannel_send_action_done(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ wpa_s->dpp_chirp_bi = NULL;
+ wpabuf_free(wpa_s->dpp_presence_announcement);
+ wpa_s->dpp_presence_announcement = NULL;
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+ wpa_s->dpp_chirp_listen = 0;
+ wpa_s->dpp_chirp_freq = 0;
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+ if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+ wpas_abort_ongoing_scan(wpa_s);
+ wpa_s->scan_res_handler = NULL;
+ }
+}
+
+
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct wpa_ssid *ssid;
+ int iter = 1;
+ const char *pos;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a valid network profile for reconfiguration");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
+ return -1;
+ }
+
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ ssid->dpp_pp_key,
+ ssid->dpp_pp_key_len);
+ if (!wpa_s->dpp_reconfig_id) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to generate E-id for reconfiguration");
+ return -1;
+ }
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_reconfig_ssid = ssid;
+ wpa_s->dpp_reconfig_ssid_id = ssid->id;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = 0;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth, bool tcp)
+{
+ struct wpabuf *resp;
+
+ resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
+ auth->e_netrole, true);
+ if (!resp)
+ return -1;
+
+ if (tcp) {
+ auth->conf_resp_tcp = resp;
+ return 0;
+ }
+
+ if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
+ resp) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not find pending GAS response");
+ wpabuf_free(resp);
+ return -1;
+ }
+ auth->conf_resp = resp;
+ return 0;
+}
+
+
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int peer = -1;
+ const char *pos, *value;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ u8 *bin;
+ size_t bin_len;
+ struct wpabuf *buf;
+ bool tcp = false;
+
+ pos = os_strstr(cmd, " peer=");
+ if (pos) {
+ peer = atoi(pos + 6);
+ if (!auth || !auth->waiting_cert ||
+ (auth->peer_bi &&
+ (unsigned int) peer != auth->peer_bi->id)) {
+ auth = dpp_controller_get_auth(wpa_s->dpp, peer);
+ tcp = true;
+ }
+ }
+
+ if (!auth || !auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No authentication exchange waiting for certificate information");
+ return -1;
+ }
+
+ if (peer >= 0 &&
+ (!auth->peer_bi ||
+ (unsigned int) peer != auth->peer_bi->id) &&
+ (!auth->tmp_peer_bi ||
+ (unsigned int) peer != auth->tmp_peer_bi->id)) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " value=");
+ if (!pos)
+ return -1;
+ value = pos + 7;
+
+ pos = os_strstr(cmd, " name=");
+ if (!pos)
+ return -1;
+ pos += 6;
+
+ if (os_strncmp(pos, "status ", 7) == 0) {
+ auth->force_conf_resp_status = atoi(value);
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
+ os_free(auth->trusted_eap_server_name);
+ auth->trusted_eap_server_name = os_strdup(value);
+ return auth->trusted_eap_server_name ? 0 : -1;
+ }
+
+ bin = base64_decode(value, os_strlen(value), &bin_len);
+ if (!bin)
+ return -1;
+ buf = wpabuf_alloc_copy(bin, bin_len);
+ os_free(bin);
+
+ if (os_strncmp(pos, "caCert ", 7) == 0) {
+ wpabuf_free(auth->cacert);
+ auth->cacert = buf;
+ return 0;
+ }
+
+ if (os_strncmp(pos, "certBag ", 8) == 0) {
+ wpabuf_free(auth->certbag);
+ auth->certbag = buf;
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ wpabuf_free(buf);
+ return -1;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.h b/contrib/wpa/wpa_supplicant/dpp_supplicant.h
index 9ba315f55254..b0d5fcf18835 100644
--- a/contrib/wpa/wpa_supplicant/dpp_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.h
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,10 +10,17 @@
#ifndef DPP_SUPPLICANT_H
#define DPP_SUPPLICANT_H
+enum dpp_status_error;
+
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
+void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, unsigned int duration);
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
@@ -26,5 +34,12 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result);
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
#endif /* DPP_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/driver_i.h b/contrib/wpa/wpa_supplicant/driver_i.h
index cf9972a6b7d5..237f4e08516f 100644
--- a/contrib/wpa/wpa_supplicant/driver_i.h
+++ b/contrib/wpa/wpa_supplicant/driver_i.h
@@ -124,13 +124,8 @@ static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
return -1;
}
-static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
- struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->driver->get_scan_results2)
- return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
- return NULL;
-}
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
{
@@ -152,18 +147,38 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
+{
+ struct wpa_driver_set_key_params params;
+
+ os_memset(&params, 0, sizeof(params));
+ params.ifname = wpa_s->ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.key_flag = key_flag;
+
if (alg != WPA_ALG_NONE) {
- if (key_idx >= 0 && key_idx <= 6)
+ /* keyidx = 1 can be either a broadcast or--with
+ * Extended Key ID--a unicast key. Use bit 15 for
+ * the pairwise keyidx 1 which is hopefully high enough
+ * to not clash with future extensions.
+ */
+ if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE))
+ wpa_s->keys_cleared &= ~BIT(15);
+ else if (key_idx >= 0 && key_idx <= 5)
wpa_s->keys_cleared &= ~BIT(key_idx);
else
wpa_s->keys_cleared = 0;
}
if (wpa_s->driver->set_key) {
- return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
- alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ return wpa_s->driver->set_key(wpa_s->drv_priv, &params);
}
return -1;
}
@@ -304,12 +319,12 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
const u8 *data, size_t data_len, int noack,
- unsigned int freq)
+ unsigned int freq, unsigned int wait)
{
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack,
- freq, NULL, 0);
+ freq, NULL, 0, 0, wait);
return -1;
}
@@ -347,6 +362,17 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
+ const u8 *dest, u16 proto,
+ const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ if (!wpa_s->driver->tx_control_port)
+ return -1;
+ return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto,
+ buf, len, no_encrypt);
+}
+
static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
@@ -494,13 +520,8 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
return -1;
}
-static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
- struct wpa_signal_info *si)
-{
- if (wpa_s->driver->signal_poll)
- return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
- return -1;
-}
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si);
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
@@ -681,6 +702,13 @@ static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
qos_map_set_len);
}
+static inline int wpa_drv_get_wowlan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->get_wowlan)
+ return 0;
+ return wpa_s->driver->get_wowlan(wpa_s->drv_priv);
+}
+
static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
const struct wowlan_triggers *triggers)
{
@@ -691,12 +719,14 @@ static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
int vendor_id, int subcmd, const u8 *data,
- size_t data_len, struct wpabuf *buf)
+ size_t data_len,
+ enum nested_attr nested_attr_flag,
+ struct wpabuf *buf)
{
if (!wpa_s->driver->vendor_cmd)
return -1;
return wpa_s->driver->vendor_cmd(wpa_s->drv_priv, vendor_id, subcmd,
- data, data_len, buf);
+ data, data_len, nested_attr_flag, buf);
}
static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
@@ -750,7 +780,7 @@ static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_protect_frames)
return -1;
@@ -758,7 +788,7 @@ static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_encrypt)
return -1;
@@ -766,7 +796,7 @@ static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
- Boolean enabled, u32 window)
+ bool enabled, u32 window)
{
if (!wpa_s->driver->set_replay_protect)
return -1;
@@ -783,7 +813,7 @@ static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_controlled_port)
return -1;
@@ -924,11 +954,11 @@ static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_MACSEC */
static inline int wpa_drv_setband(struct wpa_supplicant *wpa_s,
- enum set_band band)
+ u32 band_mask)
{
if (!wpa_s->driver->set_band)
return -1;
- return wpa_s->driver->set_band(wpa_s->drv_priv, band);
+ return wpa_s->driver->set_band(wpa_s->drv_priv, band_mask);
}
static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s,
@@ -1041,14 +1071,14 @@ static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
}
-static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
- unsigned int num_bssid,
- const u8 *bssids)
+static inline int wpa_drv_set_bssid_tmp_disallow(struct wpa_supplicant *wpa_s,
+ unsigned int num_bssid,
+ const u8 *bssids)
{
- if (!wpa_s->driver->set_bssid_blacklist)
+ if (!wpa_s->driver->set_bssid_tmp_disallow)
return -1;
- return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
- bssids);
+ return wpa_s->driver->set_bssid_tmp_disallow(wpa_s->drv_priv, num_bssid,
+ bssids);
}
static inline int wpa_drv_update_connect_params(
@@ -1080,4 +1110,11 @@ static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
wpa_s->bridge_ifname, val);
}
+static inline int wpa_drv_dpp_listen(struct wpa_supplicant *wpa_s, bool enable)
+{
+ if (!wpa_s->driver->dpp_listen)
+ return 0;
+ return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable);
+}
+
#endif /* DRIVER_I_H */
diff --git a/contrib/wpa/wpa_supplicant/eapol_test.c b/contrib/wpa/wpa_supplicant/eapol_test.c
index 524724f19735..e256ac50eec4 100644
--- a/contrib/wpa/wpa_supplicant/eapol_test.c
+++ b/contrib/wpa/wpa_supplicant/eapol_test.c
@@ -439,7 +439,7 @@ static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
static void eapol_test_write_cert(FILE *f, const char *subject,
const struct wpabuf *cert)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
if (encoded == NULL)
@@ -644,9 +644,9 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
return 0;
}
@@ -674,10 +674,8 @@ static void test_eapol_clean(struct eapol_test_data *e,
os_free(e->radius_conf);
e->radius_conf = NULL;
scard_deinit(wpa_s->scard);
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
@@ -1025,6 +1023,7 @@ static void wpa_init_conf(struct eapol_test_data *e,
*pos++ = a[1];
*pos++ = a[2];
*pos++ = a[3];
+ as->addr.af = AF_INET;
}
#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
if (hostapd_parse_ip_addr(authsrv, &as->addr) < 0) {
@@ -1390,7 +1389,7 @@ int main(int argc, char *argv[])
eapol_test.ctrl_iface = 1;
break;
case 'v':
- printf("eapol_test v" VERSION_STR "\n");
+ printf("eapol_test v%s\n", VERSION_STR);
return 0;
case 'W':
wait_for_monitor++;
diff --git a/contrib/wpa/wpa_supplicant/events.c b/contrib/wpa/wpa_supplicant/events.c
index 87dad0811e30..a565e658f33d 100644
--- a/contrib/wpa/wpa_supplicant/events.c
+++ b/contrib/wpa/wpa_supplicant/events.c
@@ -30,8 +30,9 @@
#include "common/ieee802_11_common.h"
#include "common/gas_server.h"
#include "common/dpp.h"
+#include "common/ptksa_cache.h"
#include "crypto/random.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
@@ -188,6 +189,16 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
drv_ssid_len) == 0)
return 0; /* current profile still in use */
+#ifdef CONFIG_OWE
+ if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_s->current_bss &&
+ (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) &&
+ drv_ssid_len == wpa_s->current_bss->ssid_len &&
+ os_memcmp(drv_ssid, wpa_s->current_bss->ssid,
+ drv_ssid_len) == 0)
+ return 0; /* current profile still in use */
+#endif /* CONFIG_OWE */
+
wpa_msg(wpa_s, MSG_DEBUG,
"Driver-initiated BSS selection changed the SSID to %s",
wpa_ssid_txt(drv_ssid, drv_ssid_len));
@@ -312,12 +323,13 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
if (bssid_changed)
wpas_notify_bssid_changed(wpa_s);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ wpa_s->drv_authorized_port = 0;
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -326,6 +338,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
wnm_clear_coloc_intf_reporting(wpa_s);
+ wpa_s->disable_mbo_oce = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
@@ -344,6 +357,9 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
int pmksa_set = -1;
size_t i;
+ /* Start with assumption of no PMKSA cache entry match */
+ pmksa_cache_clear_current(wpa_s->wpa);
+
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
ie.pmkid == NULL)
return;
@@ -477,6 +493,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_SCAN_PROCESSING
+#ifdef CONFIG_WEP
static int has_wep_key(struct wpa_ssid *ssid)
{
int i;
@@ -488,6 +505,7 @@ static int has_wep_key(struct wpa_ssid *ssid)
return 0;
}
+#endif /* CONFIG_WEP */
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
@@ -508,8 +526,10 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
if (has_wep_key(ssid))
privacy = 1;
+#endif /* CONFIG_WEP */
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -538,17 +558,21 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
int proto_match = 0;
const u8 *rsn_ie, *wpa_ie;
int ret;
+#ifdef CONFIG_WEP
int wep_ok;
+#endif /* CONFIG_WEP */
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
return ret;
+#ifdef CONFIG_WEP
/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+#endif /* CONFIG_WEP */
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
@@ -565,6 +589,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
if (!ie.has_group)
ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -573,6 +598,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" selected based on TSN in RSN IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto) &&
!(ssid->proto & WPA_PROTO_OSEN)) {
@@ -611,7 +637,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
break;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
@@ -620,7 +645,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" skip RSN IE - no mgmt frame protection");
break;
}
-#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
@@ -629,17 +653,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
-#ifdef CONFIG_MBO
- if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
- wpas_get_ssid_pmf(wpa_s, ssid) !=
- NO_MGMT_FRAME_PROTECTION) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
- break;
- }
-#endif /* CONFIG_MBO */
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -647,7 +660,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
return 1;
}
-#ifdef CONFIG_IEEE80211W
if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
(!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
if (debug_print)
@@ -655,7 +667,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" skip - MFP Required but network not MFP Capable");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
@@ -668,6 +679,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
break;
}
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -676,6 +688,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
" selected based on TSN in WPA IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto)) {
if (debug_print)
@@ -785,8 +798,8 @@ static int freq_allowed(int *freqs, int freq)
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int debug_print)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss, int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -863,6 +876,28 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
continue;
}
+#ifdef CONFIG_SAE
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
+ if (wpa_s->conf->sae_pwe == 0 &&
+ !ssid->sae_password_id &&
+ wpa_key_mgmt_sae(ssid->key_mgmt)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " SAE H2E disabled");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_sae_h2e_only) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TESTING: Ignore SAE H2E requirement mismatch");
+ continue;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return 0;
+ }
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
if (!flagged)
continue;
@@ -964,6 +999,24 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
*ret_ssid = pos;
*ret_ssid_len = ssid_len;
+ if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid))
+ continue;
+ if (ssid->ssid_len == ssid_len &&
+ os_memcmp(ssid->ssid, pos, ssid_len) == 0) {
+ /* OWE BSS in transition mode for a currently
+ * enabled OWE network. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode OWE SSID for active OWE profile");
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
+ break;
+ }
+ }
+ }
+
if (bss->ssid_len > 0)
return;
@@ -1004,36 +1057,431 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_ssid_txt(pos, ssid_len));
os_memcpy(bss->ssid, pos, ssid_len);
bss->ssid_len = ssid_len;
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
#endif /* CONFIG_OWE */
}
+static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+ int i, j;
+
+ if (!wpa_s->hw.modes || !wpa_s->hw.num_modes)
+ return 0;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[j];
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->freq == freq)
+ return !!(chan->flag & HOSTAPD_CHAN_DISABLED);
+ }
+ }
+
+ return 1;
+}
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, int bssid_ignore_count,
+ bool debug_print);
+
+
+#ifdef CONFIG_SAE_PK
+static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *orig_bss,
+ struct wpa_ssid *ssid,
+ const u8 *match_ssid,
+ size_t match_ssid_len)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ int count;
+ const u8 *ie;
+
+ if (bss == orig_bss)
+ continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (!(ieee802_11_rsnx_capab(ie, WLAN_RSNX_CAPAB_SAE_PK)))
+ continue;
+
+ /* TODO: Could be more thorough in checking what kind of
+ * signal strength or throughput estimate would be acceptable
+ * compared to the originally selected BSS. */
+ if (bss->est_throughput < 2000)
+ return false;
+
+ count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, count, 0))
+ return true;
+ }
+
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, int bssid_ignore_count,
+ bool debug_print)
+{
+ int res;
+ bool wpa, check_ssid, osen, rsn_osen = false;
+ struct wpa_ie_data data;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_SAE
+ u8 rsnxe_capa = 0;
+#endif /* CONFIG_SAE */
+ const u8 *ie;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ wpa = ie && ie[1];
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ wpa |= ie && ie[1];
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = true;
+ ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+ osen = ie != NULL;
+
+#ifdef CONFIG_SAE
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+#endif /* CONFIG_SAE */
+
+ check_ssid = wpa || ssid->ssid_len > 0;
+
+ if (wpas_network_disabled(wpa_s, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ return false;
+ }
+
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
+ return false;
+ }
+
+#ifdef CONFIG_WPS
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && bssid_ignore_count) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID ignored (WPS)");
+ return false;
+ }
+
+ if (wpa && ssid->ssid_len == 0 &&
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+ check_ssid = false;
+
+ if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ /* Only allow wildcard SSID match if an AP advertises active
+ * WPS operation that matches our mode. */
+ check_ssid = ssid->ssid_len > 0 ||
+ !wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss);
+ }
+#endif /* CONFIG_WPS */
+
+ if (ssid->bssid_set && ssid->ssid_len == 0 &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+ check_ssid = false;
+
+ if (check_ssid &&
+ (match_ssid_len != ssid->ssid_len ||
+ os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ return false;
+ }
+
+ if (ssid->bssid_set &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ return false;
+ }
+
+ /* check the list of BSSIDs to ignore */
+ if (ssid->num_bssid_ignore &&
+ addr_in_list(bss->bssid, ssid->bssid_ignore,
+ ssid->num_bssid_ignore)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID configured to be ignored");
+ return false;
+ }
+
+ /* if there is a list of accepted BSSIDs, only accept those APs */
+ if (ssid->num_bssid_accept &&
+ !addr_in_list(bss->bssid, ssid->bssid_accept,
+ ssid->num_bssid_accept)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in list of accepted values");
+ return false;
+ }
+
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
+ return false;
+
+ if (!osen && !wpa &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_WEP
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
+ return false;
+ }
+#endif /* CONFIG_WEP */
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
+ return false;
+ }
+
+ if (!wpa_supplicant_match_privacy(bss, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy mismatch");
+ return false;
+ }
+
+ if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ return false;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
+ return false;
+ }
+
+ if (!freq_allowed(ssid->freq_list, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_MESH
+ if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
+ return false;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ return false;
+ }
+
+#ifdef CONFIG_SAE
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE-PK required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ return false;
+ }
+#endif /* !CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ return false;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
+ return false;
+ }
+ p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p_ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
+ return false;
+ }
+
+ if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 ||
+ os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
+ wpabuf_free(p2p_ie);
+ return false;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
+ /*
+ * TODO: skip the AP if its P2P IE has Group Formation bit set in the
+ * P2P Group Capability Bitmap and we are not in Group Formation with
+ * that device.
+ */
+#endif /* CONFIG_P2P */
+
+ if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time)) {
+ struct os_reltime diff;
+
+ os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ return false;
+ }
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ return false;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - AP temporarily disallowed");
+ return false;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no PMKSA entry for DPP");
+ return false;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_AUTOMATIC &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ sae_pk_acceptable_bss_with_pk(wpa_s, bss, ssid, match_ssid,
+ match_ssid_len)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - another acceptable BSS with SAE-PK in the same ESS");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (bss->ssid_len == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no SSID known for the BSS");
+ return false;
+ }
+
+ /* Matching configuration found */
+ return true;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
- int wpa;
- struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen, rsn_osen = 0;
-#ifdef CONFIG_MBO
- const u8 *assoc_disallow;
-#endif /* CONFIG_MBO */
+ int osen;
const u8 *match_ssid;
size_t match_ssid_len;
- struct wpa_ie_data data;
+ int bssid_ignore_count;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
- if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN))
- rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1053,13 +1501,13 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
osen ? " osen=1" : "");
}
- e = wpa_blacklist_get(wpa_s, bss->bssid);
- if (e) {
+ bssid_ignore_count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
+ if (bssid_ignore_count) {
int limit = 1;
if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
/*
* When only a single network is enabled, we can
- * trigger blacklisting on the first failure. This
+ * trigger BSSID ignoring on the first failure. This
* should not be done with multiple enabled networks to
* avoid getting forced to move into a worse ESS on
* single error if there are no other BSSes of the
@@ -1067,11 +1515,11 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
*/
limit = 0;
}
- if (e->count > limit) {
+ if (bssid_ignore_count > limit) {
if (debug_print) {
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (count=%d limit=%d)",
- e->count, limit);
+ " skip - BSSID ignored (count=%d limit=%d)",
+ bssid_ignore_count, limit);
}
return NULL;
}
@@ -1099,283 +1547,16 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
- wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
+ if (disabled_freq(wpa_s, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - channel disabled");
+ return NULL;
+ }
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
- int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
- int res;
-
- if (wpas_network_disabled(wpa_s, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
- continue;
- }
-
- res = wpas_temp_disabled(wpa_s, ssid);
- if (res > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - disabled temporarily for %d second(s)",
- res);
- continue;
- }
-
-#ifdef CONFIG_WPS
- if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (WPS)");
- continue;
- }
-
- if (wpa && ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
-
- if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
- /* Only allow wildcard SSID match if an AP
- * advertises active WPS operation that matches
- * with our mode. */
- check_ssid = 1;
- if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
- }
-#endif /* CONFIG_WPS */
-
- if (ssid->bssid_set && ssid->ssid_len == 0 &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
- check_ssid = 0;
-
- if (check_ssid &&
- (match_ssid_len != ssid->ssid_len ||
- os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SSID mismatch");
- continue;
- }
-
- if (ssid->bssid_set &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID mismatch");
- continue;
- }
-
- /* check blacklist */
- if (ssid->num_bssid_blacklist &&
- addr_in_list(bss->bssid, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
- continue;
- }
-
- /* if there is a whitelist, only accept those APs */
- if (ssid->num_bssid_whitelist &&
- !addr_in_list(bss->bssid, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
- continue;
- }
-
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
- debug_print))
- continue;
-
- if (!osen && !wpa &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-WPA network not allowed");
- continue;
- }
-
- if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
- has_wep_key(ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - ignore WPA/WPA2 AP for WEP network block");
- continue;
- }
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
- !rsn_osen) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-OSEN network not allowed");
- continue;
- }
-
- if (!wpa_supplicant_match_privacy(bss, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - privacy mismatch");
- continue;
- }
-
- if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
- !bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - not ESS, PBSS, or MBSS");
- continue;
- }
-
- if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
- continue;
- }
-
- if (!freq_allowed(ssid->freq_list, bss->freq)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed");
- continue;
- }
-
-#ifdef CONFIG_MESH
- if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
- ssid->frequency != bss->freq) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed (mesh)");
- continue;
- }
-#endif /* CONFIG_MESH */
-
- if (!rate_match(wpa_s, bss, debug_print)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - rate sets do not match");
- continue;
- }
-
-#ifndef CONFIG_IBSS_RSN
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
- WPA_KEY_MGMT_WPA_NONE))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - IBSS RSN not supported in the build");
- continue;
- }
-#endif /* !CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_P2P
- if (ssid->p2p_group &&
- !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
- !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P IE seen");
- continue;
- }
-
- if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
- struct wpabuf *p2p_ie;
- u8 dev_addr[ETH_ALEN];
-
- ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
- if (ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P element");
- continue;
- }
- p2p_ie = wpa_bss_get_vendor_ie_multi(
- bss, P2P_IE_VENDOR_TYPE);
- if (p2p_ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - could not fetch P2P element");
- continue;
- }
-
- if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
- || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
- ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no matching GO P2P Device Address in P2P element");
- wpabuf_free(p2p_ie);
- continue;
- }
- wpabuf_free(p2p_ie);
- }
-
- /*
- * TODO: skip the AP if its P2P IE has Group Formation
- * bit set in the P2P Group Capability Bitmap and we
- * are not in Group Formation with that device.
- */
-#endif /* CONFIG_P2P */
-
- if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time))
- {
- struct os_reltime diff;
-
- os_reltime_sub(&wpa_s->scan_min_time,
- &bss->last_update, &diff);
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
- (unsigned int) diff.sec,
- (unsigned int) diff.usec);
- continue;
- }
-#ifdef CONFIG_MBO
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->ignore_assoc_disallow)
- goto skip_assoc_disallow;
-#endif /* CONFIG_TESTING_OPTIONS */
- assoc_disallow = wpas_mbo_get_bss_attr(
- bss, MBO_ATTR_ID_ASSOC_DISALLOW);
- if (assoc_disallow && assoc_disallow[1] >= 1) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
- assoc_disallow[2]);
- continue;
- }
-
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - AP temporarily disallowed");
- continue;
- }
-#ifdef CONFIG_TESTING_OPTIONS
- skip_assoc_disallow:
-#endif /* CONFIG_TESTING_OPTIONS */
-#endif /* CONFIG_MBO */
-
-#ifdef CONFIG_DPP
- if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
- !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
- (!ssid->dpp_connector ||
- !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no PMKSA entry for DPP");
- continue;
- }
-#endif /* CONFIG_DPP */
-
- /* Matching configuration found */
- return ssid;
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, bssid_ignore_count, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1426,8 +1607,9 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
- wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected %sBSS " MACSTR
" ssid='%s'",
+ bss == wpa_s->current_bss ? "current ": "",
MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len));
return bss;
@@ -1441,7 +1623,7 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
- int prio;
+ size_t prio;
struct wpa_ssid *next_ssid = NULL;
struct wpa_ssid *ssid;
@@ -1475,12 +1657,12 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
break;
}
- if (selected == NULL && wpa_s->blacklist &&
+ if (selected == NULL && wpa_s->bssid_ignore &&
!wpa_s->countermeasures) {
- wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
- "blacklist and try again");
- wpa_blacklist_clear(wpa_s);
- wpa_s->blacklist_cleared++;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "No APs found - clear BSSID ignore list and try again");
+ wpa_bssid_ignore_clear(wpa_s);
+ wpa_s->bssid_ignore_cleared = true;
} else if (selected == NULL)
break;
}
@@ -1596,7 +1778,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
static struct wpa_ssid *
wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
@@ -1652,46 +1834,41 @@ static void wpa_supplicant_rsn_preauth_scan_results(
}
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
- struct wpa_bss *selected,
- struct wpa_ssid *ssid)
-{
- struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
- int min_diff, diff;
- int to_5ghz;
- int cur_est, sel_est;
-#endif /* CONFIG_NO_ROAMING */
- if (wpa_s->reassociate)
- return 1; /* explicit request to reassociate */
- if (wpa_s->wpa_state < WPA_ASSOCIATED)
- return 1; /* we are not associated; continue */
- if (wpa_s->current_ssid == NULL)
- return 1; /* unknown current SSID */
- if (wpa_s->current_ssid != ssid)
- return 1; /* different network block */
+static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise)
+{
+ if (noise == WPA_INVALID_NOISE)
+ noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ return avg_signal - noise;
+}
- if (wpas_driver_bss_selection(wpa_s))
- return 0; /* Driver-based roaming */
- if (wpa_s->current_ssid->ssid)
- current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
- wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid_len);
- if (!current_bss)
- current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+static unsigned int
+wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
+ const struct wpa_bss *bss, int snr)
+{
+ int rate = wpa_bss_get_max_rate(bss);
+ const u8 *ies = wpa_bss_ie_ptr(bss);
+ size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
- if (!current_bss)
- return 1; /* current BSS not seen in scan results */
+ return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, bss->freq);
+}
- if (current_bss == selected)
- return 0;
- if (selected->last_update_idx > current_bss->last_update_idx)
- return 1; /* current BSS not seen in the last scan */
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *selected)
+{
+ int min_diff, diff;
+ int to_5ghz;
+ int cur_level;
+ unsigned int cur_est, sel_est;
+ struct wpa_signal_info si;
+ int cur_snr = 0;
+ int ret = 0;
-#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
" freq=%d level=%d snr=%d est_throughput=%u",
@@ -1711,7 +1888,41 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
- if (selected->est_throughput > current_bss->est_throughput + 5000) {
+ cur_level = current_bss->level;
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
+
+ /*
+ * Try to poll the signal from the driver since this will allow to get
+ * more accurate values. In some cases, there can be big differences
+ * between the RSSI of the Probe Response frames of the AP we are
+ * associated with and the Beacon frames we hear from the same AP after
+ * association. This can happen, e.g., when there are two antennas that
+ * hear the AP very differently. If the driver chooses to hear the
+ * Probe Response frames during the scan on the "bad" antenna because
+ * it wants to save power, but knows to choose the other antenna after
+ * association, we will hear our AP with a low RSSI as part of the
+ * scan even when we can hear it decently on the other antenna. To cope
+ * with this, ask the driver to teach us how it hears the AP. Also, the
+ * scan results may be a bit old, since we can very quickly get fresh
+ * information about our currently associated AP.
+ */
+ if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
+ (si.avg_beacon_signal || si.avg_signal)) {
+ cur_level = si.avg_beacon_signal ? si.avg_beacon_signal :
+ si.avg_signal;
+ cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
+ si.current_noise);
+
+ cur_est = wpas_get_est_throughput_from_bss_snr(wpa_s,
+ current_bss,
+ cur_snr);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
+ cur_level, cur_snr, cur_est);
+ }
+
+ if (sel_est > cur_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Allow reassociation - selected BSS has better estimated throughput");
return 1;
@@ -1719,70 +1930,121 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
- if (current_bss->level < 0 &&
- current_bss->level > selected->level + to_5ghz * 2) {
+ if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 &&
+ sel_est < cur_est * 1.2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
}
- if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ if (cur_est > sel_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - Current BSS has better estimated throughput");
return 0;
}
- cur_est = current_bss->est_throughput;
- sel_est = selected->est_throughput;
- min_diff = 2;
- if (current_bss->level < 0) {
- if (current_bss->level < -85)
- min_diff = 1;
- else if (current_bss->level < -80)
- min_diff = 2;
- else if (current_bss->level < -75)
- min_diff = 3;
- else if (current_bss->level < -70)
- min_diff = 4;
- else
- min_diff = 5;
- if (cur_est > sel_est * 1.5)
- min_diff += 10;
- else if (cur_est > sel_est * 1.2)
- min_diff += 5;
- else if (cur_est > sel_est * 1.1)
- min_diff += 2;
- else if (cur_est > sel_est)
- min_diff++;
- }
- if (to_5ghz) {
- int reduce = 2;
-
- /* Make it easier to move to 5 GHz band */
- if (sel_est > cur_est * 1.5)
- reduce = 5;
- else if (sel_est > cur_est * 1.2)
- reduce = 4;
- else if (sel_est > cur_est * 1.1)
- reduce = 3;
-
- if (min_diff > reduce)
- min_diff -= reduce;
- else
- min_diff = 0;
+ if (cur_snr > GREAT_SNR) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has good SNR (%u > %u)",
+ cur_snr, GREAT_SNR);
+ return 0;
}
- diff = abs(current_bss->level - selected->level);
+
+ if (cur_level < -85) /* ..-86 dBm */
+ min_diff = 1;
+ else if (cur_level < -80) /* -85..-81 dBm */
+ min_diff = 2;
+ else if (cur_level < -75) /* -80..-76 dBm */
+ min_diff = 3;
+ else if (cur_level < -70) /* -75..-71 dBm */
+ min_diff = 4;
+ else if (cur_level < 0) /* -70..-1 dBm */
+ min_diff = 5;
+ else /* unspecified units (not in dBm) */
+ min_diff = 2;
+
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
+ else if (sel_est > cur_est * 1.5)
+ min_diff -= 10;
+ else if (sel_est > cur_est * 1.2)
+ min_diff -= 5;
+ else if (sel_est > cur_est * 1.1)
+ min_diff -= 2;
+ else if (sel_est > cur_est)
+ min_diff--;
+
+ if (to_5ghz)
+ min_diff -= 2;
+ diff = selected->level - cur_level;
if (diff < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
diff, min_diff);
- return 0;
+ ret = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
+ ret = 1;
}
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "%scur_bssid=" MACSTR
+ " cur_freq=%d cur_level=%d cur_est=%d sel_bssid=" MACSTR
+ " sel_freq=%d sel_level=%d sel_est=%d",
+ ret ? WPA_EVENT_DO_ROAM : WPA_EVENT_SKIP_ROAM,
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, cur_level, cur_est,
+ MAC2STR(selected->bssid),
+ selected->freq, selected->level, sel_est);
+ return ret;
+}
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Allow reassociation due to difference in signal level (%d >= %d)",
- diff, min_diff);
- return 1;
+#endif /* CONFIG_NO_ROAMING */
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *selected,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_bss *current_bss = NULL;
+
+ if (wpa_s->reassociate)
+ return 1; /* explicit request to reassociate */
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return 1; /* we are not associated; continue */
+ if (wpa_s->current_ssid == NULL)
+ return 1; /* unknown current SSID */
+ if (wpa_s->current_ssid != ssid)
+ return 1; /* different network block */
+
+ if (wpas_driver_bss_selection(wpa_s))
+ return 0; /* Driver-based roaming */
+
+ if (wpa_s->current_ssid->ssid)
+ current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len);
+ if (!current_bss)
+ current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+ if (!current_bss)
+ return 1; /* current BSS not seen in scan results */
+
+ if (current_bss == selected)
+ return 0;
+
+ if (selected->last_update_idx > current_bss->last_update_idx)
+ return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+ return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
+ selected);
#else /* CONFIG_NO_ROAMING */
return 0;
#endif /* CONFIG_NO_ROAMING */
@@ -1827,9 +2089,18 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return -1;
if (data && data->scan_info.external_scan)
return -1;
- wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
- "scanning again");
- wpa_supplicant_req_new_scan(wpa_s, 1, 0);
+ if (wpa_s->scan_res_fail_handler) {
+ void (*handler)(struct wpa_supplicant *wpa_s);
+
+ handler = wpa_s->scan_res_fail_handler;
+ wpa_s->scan_res_fail_handler = NULL;
+ handler(wpa_s);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to get scan results - try scanning again");
+ wpa_supplicant_req_new_scan(wpa_s, 1, 0);
+ }
+
ret = -1;
goto scan_work_done;
}
@@ -1867,15 +2138,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
goto scan_work_done;
}
- if (ap) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface->scan_cb)
- wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
-#endif /* CONFIG_AP */
- goto scan_work_done;
- }
-
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
wpa_s->own_scan_running,
data ? data->scan_info.external_scan : 0);
@@ -1892,6 +2154,15 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_notify_scan_done(wpa_s, 1);
+ if (ap) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface->scan_cb)
+ wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+ goto scan_work_done;
+ }
+
if (data && data->scan_info.external_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
@@ -1901,7 +2172,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (wnm_scan_process(wpa_s, 1) > 0)
goto scan_work_done;
- if (sme_proc_obss_scan(wpa_s) > 0)
+ if (sme_proc_obss_scan(wpa_s, scan_res) > 0)
goto scan_work_done;
if (own_request && data &&
@@ -1937,6 +2208,21 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
radio_work_done(work);
}
+ os_free(wpa_s->last_scan_freqs);
+ wpa_s->last_scan_freqs = NULL;
+ wpa_s->num_last_scan_freqs = 0;
+ if (own_request && data &&
+ data->scan_info.freqs && data->scan_info.num_freqs) {
+ wpa_s->last_scan_freqs = os_malloc(sizeof(int) *
+ data->scan_info.num_freqs);
+ if (wpa_s->last_scan_freqs) {
+ os_memcpy(wpa_s->last_scan_freqs,
+ data->scan_info.freqs,
+ sizeof(int) * data->scan_info.num_freqs);
+ wpa_s->num_last_scan_freqs = data->scan_info.num_freqs;
+ }
+ }
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -1990,6 +2276,8 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
return 0;
}
+ wpa_s->suitable_network++;
+
if (ssid != wpa_s->current_ssid &&
wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_s->own_disconnect_req = 1;
@@ -2010,6 +2298,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
*/
return 1;
} else {
+ wpa_s->no_suitable_network++;
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2156,7 +2445,8 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
return -1;
os_get_reltime(&now);
- if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+ if (os_reltime_expired(&now, &wpa_s->last_scan,
+ wpa_s->conf->scan_res_valid_for_connect)) {
wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
return -1;
}
@@ -2289,28 +2579,41 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
const u8 *map_sub_elem, *pos;
size_t len;
- if (!wpa_s->current_ssid ||
- !wpa_s->current_ssid->multi_ap_backhaul_sta ||
- !ies ||
- ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
- return;
+ wpa_s->multi_ap_ie = 0;
- if (!elems.multi_ap || elems.multi_ap_len < 7) {
- wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
- goto fail;
- }
+ if (!ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed ||
+ !elems.multi_ap || elems.multi_ap_len < 7)
+ return;
pos = elems.multi_ap + 4;
len = elems.multi_ap_len - 4;
map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
- if (!map_sub_elem || map_sub_elem[1] < 1) {
- wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+ if (!map_sub_elem || map_sub_elem[1] < 1)
+ return;
+
+ wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS);
+ wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] &
+ MULTI_AP_FRONTHAUL_BSS);
+ wpa_s->multi_ap_ie = 1;
+}
+
+
+static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta)
+ return;
+
+ if (!wpa_s->multi_ap_ie) {
+ wpa_printf(MSG_INFO,
+ "AP does not include valid Multi-AP element");
goto fail;
}
- if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
- if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+ if (!wpa_s->multi_ap_backhaul) {
+ if (wpa_s->multi_ap_fronthaul &&
wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
wpa_printf(MSG_INFO,
"WPS active, accepting fronthaul-only BSS");
@@ -2380,13 +2683,13 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
+ bool bssid_known;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+ bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
if (data->assoc_info.req_ies)
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
@@ -2434,8 +2737,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wpa_s->connection_set = 1;
wpa_s->connection_ht = req_elems.ht_capabilities &&
resp_elems.ht_capabilities;
+ /* Do not include subset of VHT on 2.4 GHz vendor
+ * extension in consideration for reporting VHT
+ * association. */
wpa_s->connection_vht = req_elems.vht_capabilities &&
- resp_elems.vht_capabilities;
+ resp_elems.vht_capabilities &&
+ (!data->assoc_info.freq ||
+ wpas_freq_to_band(data->assoc_info.freq) !=
+ BAND_2_4_GHZ);
wpa_s->connection_he = req_elems.he_capabilities &&
resp_elems.he_capabilities;
}
@@ -2452,22 +2761,29 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
@@ -2490,7 +2806,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OWE
if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
- (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ (!bssid_known ||
owe_process_assoc_resp(wpa_s->wpa, bssid,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len) < 0)) {
@@ -2501,7 +2817,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+ if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_s->dpp_pfs) {
struct ieee802_11_elems elems;
if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
@@ -2524,7 +2841,7 @@ no_pfs:
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2584,7 +2901,7 @@ no_pfs:
/* Process FT when SME is in the driver */
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
wpa_ft_is_completed(wpa_s->wpa)) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2602,6 +2919,11 @@ no_pfs:
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
+ if (bssid_known)
+ wpas_handle_assoc_resp_mscs(wpa_s, bssid,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+
/* WPA/RSN IE from Beacon/ProbeResp */
p = data->assoc_info.beacon_ies;
l = data->assoc_info.beacon_ies_len;
@@ -2629,14 +2951,19 @@ no_pfs:
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
+ if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
- if (!rsn_found && data->assoc_info.beacon_ies)
+ if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ }
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -2656,7 +2983,7 @@ no_pfs:
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
- const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -2667,11 +2994,14 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
return 0;
@@ -2706,7 +3036,7 @@ static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
if (!bss)
return;
- ieprb = (const u8 *) (bss + 1);
+ ieprb = wpa_bss_ie_ptr(bss);
iebcn = ieprb + bss->ie_len;
if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
@@ -2723,6 +3053,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
int ft_completed, already_authorized;
int new_bss = 0;
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ struct wpa_bss *bss;
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2738,6 +3071,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_AP */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->own_reconnect_req = 0;
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
@@ -2787,6 +3121,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
}
}
+ multi_ap_set_4addr_mode(wpa_s);
+
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss)
@@ -2817,7 +3153,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
already_authorized = data && data->assoc_info.authorized;
/*
- * Set portEnabled first to FALSE in order to get EAP state machine out
+ * Set portEnabled first to false in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
* state machine may transit to AUTHENTICATING state based on obsolete
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
@@ -2825,16 +3161,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* reset the state.
*/
if (!ft_completed && !already_authorized) {
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
}
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
- already_authorized)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ already_authorized || wpa_s->drv_authorized_port)
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
wpa_s->eapol_received = 0;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
@@ -2866,8 +3202,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
@@ -2876,8 +3212,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
*/
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -2885,11 +3221,28 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* to allow EAPOL supplicant to complete its work without
* waiting for WPA supplicant.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
wpa_s->last_eapol_matches_bssid = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsne_override_eapol) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE EAPOL-Key msg 2/4 override");
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsne_override_eapol),
+ wpabuf_len(wpa_s->rsne_override_eapol));
+ }
+ if (wpa_s->rsnxe_override_eapol) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE EAPOL-Key msg 2/4 override");
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsnxe_override_eapol),
+ wpabuf_len(wpa_s->rsnxe_override_eapol));
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (wpa_s->pending_eapol_rx) {
struct os_reltime now, age;
os_get_reltime(&now);
@@ -2909,6 +3262,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->pending_eapol_rx = NULL;
}
+#ifdef CONFIG_WEP
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_s->current_ssid &&
@@ -2916,6 +3270,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IBSS_RSN
if (wpa_s->current_ssid &&
@@ -2946,15 +3301,25 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wmm_ac_restore_tspecs(wpa_s);
}
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
if (fils_cache_id)
wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
}
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP2
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
}
@@ -2999,8 +3364,10 @@ static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
int locally_generated)
{
if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
- !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
- return 0; /* Not in 4-way handshake with PSK */
+ !wpa_s->new_connection ||
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_key_mgmt_sae(wpa_s->key_mgmt))
+ return 0; /* Not in initial 4-way handshake with PSK */
/*
* It looks like connection was lost while trying to go through PSK
@@ -3062,6 +3429,10 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY");
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s,
+ DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
@@ -3076,21 +3447,25 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_COMPLETED &&
wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
- !locally_generated &&
- disconnect_reason_recoverable(reason_code)) {
+ (wpa_s->own_reconnect_req ||
+ (!locally_generated &&
+ disconnect_reason_recoverable(reason_code)))) {
/*
* It looks like the AP has dropped association with
- * us, but could allow us to get back in. Try to
- * reconnect to the same BSS without full scan to save
- * time for some common cases.
+ * us, but could allow us to get back in. This is also
+ * triggered for cases where local reconnection request
+ * is used to force reassociation with the same BSS.
+ * Try to reconnect to the same BSS without a full scan
+ * to save time for some common cases.
*/
fast_reconnect = wpa_s->current_bss;
fast_reconnect_ssid = wpa_s->current_ssid;
- } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+ } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) {
wpa_supplicant_req_scan(wpa_s, 0, 100000);
- else
+ } else {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
"immediate scan");
+ }
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
"try to re-connect");
@@ -3105,6 +3480,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
wpas_connection_failed(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
+ ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE);
+
if (locally_generated)
wpa_s->disconnect_reason = -reason_code;
else
@@ -3198,7 +3575,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
/* initialize countermeasures */
wpa_s->countermeasures = 1;
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_bssid_ignore_add(wpa_s, wpa_s->bssid);
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
@@ -3510,26 +3887,22 @@ static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
struct unprot_deauth *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
struct unprot_disassoc *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
@@ -3787,14 +4160,12 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_SME
if (category == WLAN_ACTION_SA_QUERY) {
- sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
+ sme_sa_query_rx(wpa_s, mgmt->da, mgmt->sa, payload, plen);
return;
}
#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
@@ -3888,6 +4259,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_DPP */
+ if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+ payload[0] == ROBUST_AV_MSCS_RESP) {
+ wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
+ payload + 1, plen - 1);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -3933,8 +4311,9 @@ static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
if (wpa_s->wpa_state == WPA_ASSOCIATED) {
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ wpa_s->drv_authorized_port = 1;
}
}
@@ -4023,6 +4402,8 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
wpa_supplicant_event_port_authorized(wpa_s);
+ wpa_s->last_eapol_matches_bssid = 1;
+
wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
data->assoc_info.ptk_kck_len,
@@ -4055,6 +4436,31 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
}
+static const char * connect_fail_reason(enum sta_connect_fail_reason_codes code)
+{
+ switch (code) {
+ case STA_CONNECT_FAIL_REASON_UNSPECIFIED:
+ return "";
+ case STA_CONNECT_FAIL_REASON_NO_BSS_FOUND:
+ return "no_bss_found";
+ case STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL:
+ return "auth_tx_fail";
+ case STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED:
+ return "auth_no_ack_received";
+ case STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED:
+ return "auth_no_resp_received";
+ case STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL:
+ return "assoc_req_tx_fail";
+ case STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED:
+ return "assoc_no_ack_received";
+ case STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED:
+ return "assoc_no_resp_received";
+ default:
+ return "unknown_reason";
+ }
+}
+
+
static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -4074,21 +4480,29 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u%s%s%s",
+ "bssid=" MACSTR " status_code=%u%s%s%s%s%s",
MAC2STR(data->assoc_reject.bssid),
data->assoc_reject.status_code,
data->assoc_reject.timed_out ? " timeout" : "",
data->assoc_reject.timeout_reason ? "=" : "",
data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
+ data->assoc_reject.timeout_reason : "",
+ data->assoc_reject.reason_code !=
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED ?
+ " qca_driver_reason=" : "",
+ connect_fail_reason(data->assoc_reject.reason_code));
else
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u%s%s%s",
+ "status_code=%u%s%s%s%s%s",
data->assoc_reject.status_code,
data->assoc_reject.timed_out ? " timeout" : "",
data->assoc_reject.timeout_reason ? "=" : "",
data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
+ data->assoc_reject.timeout_reason : "",
+ data->assoc_reject.reason_code !=
+ STA_CONNECT_FAIL_REASON_UNSPECIFIED ?
+ " qca_driver_reason=" : "",
+ connect_fail_reason(data->assoc_reject.reason_code));
wpa_s->assoc_status_code = data->assoc_reject.status_code;
wpas_notify_assoc_status_code(wpa_s);
@@ -4118,6 +4532,41 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ /* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is
+ * the status code defined in the DPP R2 tech spec.
+ * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
+ * interoperability workaround with older hostapd implementation. */
+ if (DPP_VERSION > 1 && wpa_s->current_ssid &&
+ (wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP ||
+ ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)) &&
+ wpa_s->current_ssid->dpp_pfs == 0 &&
+ (data->assoc_reject.status_code ==
+ WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
+ data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+
+ wpa_s->current_ssid->dpp_pfs_fallback ^= 1;
+ if (!bss)
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ if (!bss || wpa_s->dpp_pfs_fallback) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Updated PFS policy for next try");
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy");
+ wpa_s->dpp_pfs_fallback = 1;
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_MBO
if (data->assoc_reject.status_code ==
WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
@@ -4172,6 +4621,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_FILS
/* Update ERP next sequence number */
if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+ fils_pmksa_cache_flush(wpa_s);
eapol_sm_update_erp_next_seq_num(
wpa_s->eapol,
data->assoc_reject.fils_erp_next_seq_num);
@@ -4184,11 +4634,44 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
}
+static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s,
+ struct unprot_beacon *data)
+{
+ struct wpabuf *buf;
+ int res;
+
+ if (!data || wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0)
+ return;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR,
+ MAC2STR(data->sa));
+
+ buf = wpabuf_alloc(4);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpabuf_put_u8(buf, 1); /* Dialog Token */
+ wpabuf_put_u8(buf, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE);
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG,
+ "Failed to send WNM-Notification Request frame");
+
+ wpabuf_free(buf);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+ struct os_reltime age, clear_at;
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -4244,6 +4727,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->disconnected) {
+ wpa_printf(MSG_INFO,
+ "Ignore unexpected EVENT_ASSOC in disconnected state");
+ break;
+ }
wpa_supplicant_event_assoc(wpa_s, data);
wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS;
if (data &&
@@ -4304,7 +4792,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
- wpa_s->radio->external_scan_running = 1;
+ wpa_s->radio->external_scan_req_interface = wpa_s;
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
break;
@@ -4312,7 +4800,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_s->scan_res_handler = NULL;
wpa_s->own_scan_running = 0;
- wpa_s->radio->external_scan_running = 0;
+ wpa_s->radio->external_scan_req_interface = NULL;
wpa_s->last_scan_req = NORMAL_SCAN_REQ;
break;
}
@@ -4332,7 +4820,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (!(data && data->scan_info.external_scan))
wpa_s->own_scan_running = 0;
if (data && data->scan_info.nl_scan_event)
- wpa_s->radio->external_scan_running = 0;
+ wpa_s->radio->external_scan_req_interface = NULL;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -4395,6 +4883,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
" type=%d stype=%d",
MAC2STR(data->tx_status.dst),
data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_PASN
+ if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+ data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
+ wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data,
+ data->tx_status.data_len,
+ data->tx_status.ack) == 0)
+ break;
+#endif /* CONFIG_PASN */
#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
#ifdef CONFIG_OFFCHANNEL
@@ -4490,6 +4986,26 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s->assoc_freq = data->ch_switch.freq;
wpa_s->current_ssid->frequency = data->ch_switch.freq;
+ if (wpa_s->current_bss &&
+ wpa_s->current_bss->freq != data->ch_switch.freq) {
+ wpa_s->current_bss->freq = data->ch_switch.freq;
+ notify_bss_changes(wpa_s, WPA_BSS_FREQ_CHANGED_FLAG,
+ wpa_s->current_bss);
+ }
+
+#ifdef CONFIG_SME
+ switch (data->ch_switch.ch_offset) {
+ case 1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+ break;
+ case -1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+ break;
+ default:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
+ break;
+ }
+#endif /* CONFIG_SME */
#ifdef CONFIG_AP
if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
@@ -4507,9 +5023,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_AP */
-#ifdef CONFIG_IEEE80211W
- sme_event_ch_switch(wpa_s);
-#endif /* CONFIG_IEEE80211W */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_ch_switch(wpa_s);
+
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
@@ -4609,6 +5125,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
break;
}
+#ifdef CONFIG_PASN
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ wpas_pasn_auth_rx(wpa_s, mgmt,
+ data->rx_mgmt.frame_len) != -2)
+ break;
+#endif /* CONFIG_PASN */
#ifdef CONFIG_SAE
if (stype == WLAN_FC_STYPE_AUTH &&
@@ -4676,6 +5198,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpas_p2p_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq,
data->remain_on_channel.duration);
+#ifdef CONFIG_DPP
+ wpas_dpp_remain_on_channel_cb(
+ wpa_s, data->remain_on_channel.freq,
+ data->remain_on_channel.duration);
+#endif /* CONFIG_DPP */
break;
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
#ifdef CONFIG_OFFCHANNEL
@@ -4715,6 +5242,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ eloop_cancel_timeout(wpas_clear_disabled_interface,
+ wpa_s, NULL);
wpa_supplicant_update_mac_addr(wpa_s);
wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
@@ -4783,7 +5312,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
- wpa_bss_flush(wpa_s);
+ os_reltime_age(&wpa_s->last_scan, &age);
+ if (age.sec >= wpa_s->conf->scan_res_valid_for_connect) {
+ clear_at.sec = wpa_s->conf->scan_res_valid_for_connect;
+ clear_at.usec = 0;
+ } else {
+ struct os_reltime tmp;
+
+ tmp.sec = wpa_s->conf->scan_res_valid_for_connect;
+ tmp.usec = 0;
+ os_reltime_sub(&tmp, &age, &clear_at);
+ }
+ eloop_register_timeout(clear_at.sec, clear_at.usec,
+ wpas_clear_disabled_interface,
+ wpa_s, NULL);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -4960,6 +5502,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->sta_opmode.rx_nss);
#endif /* CONFIG_AP */
break;
+ case EVENT_UNPROT_BEACON:
+ wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon);
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
@@ -4997,8 +5542,6 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
return;
wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
os_free(wpa_i);
- if (wpa_s)
- wpa_s->matched = 1;
}
#endif /* CONFIG_MATCH_IFACE */
diff --git a/contrib/wpa/wpa_supplicant/examples/dpp-nfc.py b/contrib/wpa/wpa_supplicant/examples/dpp-nfc.py
new file mode 100755
index 000000000000..8e865f3fcd33
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/examples/dpp-nfc.py
@@ -0,0 +1,1186 @@
+#!/usr/bin/python3
+#
+# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2019-2020, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import binascii
+import errno
+import os
+import struct
+import sys
+import time
+import threading
+import argparse
+
+import nfc
+import ndef
+
+import logging
+
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+no_input = False
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+netrole = None
+operation_success = False
+mutex = threading.Lock()
+
+C_NORMAL = '\033[0m'
+C_RED = '\033[91m'
+C_GREEN = '\033[92m'
+C_YELLOW = '\033[93m'
+C_BLUE = '\033[94m'
+C_MAGENTA = '\033[95m'
+C_CYAN = '\033[96m'
+
+def summary(txt, color=None):
+ with mutex:
+ if color:
+ print(color + txt + C_NORMAL)
+ else:
+ print(txt)
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError as error:
+ summary("Could not find wpa_supplicant: %s", str(error))
+ return None
+
+ if len(ifaces) < 1:
+ summary("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ if ifname and ifname not in ctrl:
+ continue
+ if os.path.basename(ctrl).startswith("p2p-dev-"):
+ # skip P2P management interface
+ continue
+ try:
+ summary("Trying to use control interface " + ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ summary("Could not connect to wpa_supplicant")
+ return None
+
+def dpp_nfc_uri_process(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ peer_id = wpas.request("DPP_NFC_URI " + uri)
+ if "FAIL" in peer_id:
+ summary("Could not parse DPP URI from NFC URI record", color=C_RED)
+ return False
+ peer_id = int(peer_id)
+ summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
+ cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+ global enrollee_only, configurator_only, config_params
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ if config_params:
+ cmd += " " + config_params
+ summary("Initiate DPP authentication: " + cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to initiate DPP Authentication", color=C_RED)
+ return False
+ summary("DPP Authentication initiated")
+ return True
+
+def dpp_hs_tag_read(record):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ summary(record)
+ if len(record.data) < 5:
+ summary("Too short DPP HS", color=C_RED)
+ return False
+ if record.data[0] != 0:
+ summary("Unexpected URI Identifier Code", color=C_RED)
+ return False
+ uribuf = record.data[1:]
+ try:
+ uri = uribuf.decode()
+ except:
+ summary("Invalid URI payload", color=C_RED)
+ return False
+ summary("URI: " + uri)
+ if not uri.startswith("DPP:"):
+ summary("Not a DPP URI", color=C_RED)
+ return False
+ return dpp_nfc_uri_process(uri)
+
+def get_status(wpas, extra=None):
+ if extra:
+ extra = "-" + extra
+ else:
+ extra = ""
+ res = wpas.request("STATUS" + extra)
+ lines = res.splitlines()
+ vals = dict()
+ for l in lines:
+ try:
+ [name, value] = l.split('=', 1)
+ except ValueError:
+ summary("Ignore unexpected status line: %s" % l)
+ continue
+ vals[name] = value
+ return vals
+
+def get_status_field(wpas, field, extra=None):
+ vals = get_status(wpas, extra)
+ if field in vals:
+ return vals[field]
+ return None
+
+def own_addr(wpas):
+ addr = get_status_field(wpas, "address")
+ if addr is None:
+ addr = get_status_field(wpas, "bssid[0]")
+ return addr
+
+def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
+ curve=None, key=None):
+ cmd = "DPP_BOOTSTRAP_GEN type=" + type
+ if chan:
+ cmd += " chan=" + chan
+ if mac:
+ if mac is True:
+ mac = own_addr(wpas)
+ if mac is None:
+ summary("Could not determine local MAC address for bootstrap info")
+ else:
+ cmd += " mac=" + mac.replace(':', '')
+ if info:
+ cmd += " info=" + info
+ if curve:
+ cmd += " curve=" + curve
+ if key:
+ cmd += " key=" + key
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ raise Exception("Failed to generate bootstrapping info")
+ return int(res)
+
+def dpp_start_listen(wpas, freq):
+ if get_status_field(wpas, "bssid[0]"):
+ summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+ if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+ summary("Enable beaconing to have radio ready for RX")
+ wpas.request("DISABLE")
+ wpas.request("SET start_disabled 0")
+ wpas.request("ENABLE")
+ cmd = "DPP_LISTEN %d" % freq
+ global enrollee_only
+ global configurator_only
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ global netrole
+ if netrole:
+ cmd += " netrole=" + netrole
+ summary(cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to start DPP listen", color=C_RED)
+ return False
+ return True
+
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
+ listen_freq = 2412
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id, chanlist
+ if chan_override:
+ chan = chan_override
+ else:
+ chan = chanlist
+ if chan and chan.startswith("81/"):
+ listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
+ if chan is None and get_status_field(wpas, "bssid[0]"):
+ freq = get_status_field(wpas, "freq")
+ if freq:
+ freq = int(freq)
+ if freq >= 2412 and freq <= 2462:
+ chan = "81/%d" % ((freq - 2407) / 5)
+ summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+ listen_freq = freq
+ if chan is None and pick_channel:
+ chan = "81/6"
+ summary("Use channel 2437 MHz since no other preference provided")
+ listen_freq = 2437
+ own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
+ res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in res:
+ return None
+ if start_listen:
+ if not dpp_start_listen(wpas, listen_freq):
+ raise Exception("Failed to start listen operation on %d MHz" % listen_freq)
+ return res
+
+def wpas_report_handover_req(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def wpas_report_handover_sel(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def dpp_handover_client(handover, alt=False):
+ summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
+ if alt:
+ handover.i_m_selector = False
+ run_dpp_handover_client(handover, alt)
+ summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
+
+def run_client_alt(handover, alt):
+ if handover.start_client_alt and not alt:
+ handover.start_client_alt = False
+ summary("Try to send alternative handover request")
+ dpp_handover_client(handover, alt=True)
+
+class HandoverClient(nfc.handover.HandoverClient):
+ def __init__(self, handover, llc):
+ super(HandoverClient, self).__init__(llc)
+ self.handover = handover
+
+ def recv_records(self, timeout=None):
+ msg = self.recv_octets(timeout)
+ if msg is None:
+ return None
+ records = list(ndef.message_decoder(msg, 'relax'))
+ if records and records[0].type == 'urn:nfc:wkt:Hs':
+ summary("Handover client received message '{0}'".format(records[0].type))
+ return list(ndef.message_decoder(msg, 'relax'))
+ summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
+ return None
+
+ def recv_octets(self, timeout=None):
+ start = time.time()
+ msg = bytearray()
+ while True:
+ poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
+ if not self.socket.poll('recv', poll_timeout):
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ try:
+ r = self.socket.recv()
+ if r is None:
+ return None
+ msg += r
+ except TypeError:
+ return b''
+ try:
+ list(ndef.message_decoder(msg, 'strict', {}))
+ return bytes(msg)
+ except ndef.DecodeError:
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ return None
+
+def run_dpp_handover_client(handover, alt=False):
+ chan_override = None
+ if alt:
+ chan_override = handover.altchanlist
+ handover.alt_proposal_used = True
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
+ uri = test_alt_uri if alt else test_uri
+ else:
+ uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
+ if uri is None:
+ summary("Cannot start handover client - no bootstrap URI available",
+ color=C_RED)
+ return
+ handover.my_uri = uri
+ uri = ndef.UriRecord(uri)
+ summary("NFC URI record for DPP: " + str(uri))
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ global test_crn
+ if test_crn:
+ prev, = struct.unpack('>H', test_crn)
+ summary("TEST MODE: Use specified crn %d" % prev)
+ crn = test_crn
+ test_crn = struct.pack('>H', prev + 0x10)
+ else:
+ crn = os.urandom(2)
+ hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
+ hr.add_alternative_carrier('active', carrier.name)
+ message = [hr, carrier]
+ summary("NFC Handover Request message for DPP: " + str(message))
+
+ if handover.peer_crn is not None and not alt:
+ summary("NFC handover request from peer was already received - do not send own")
+ return
+ if handover.client:
+ summary("Use already started handover client")
+ client = handover.client
+ else:
+ summary("Start handover client")
+ client = HandoverClient(handover, handover.llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception as e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+ handover.client = client
+
+ if handover.peer_crn is not None and not alt:
+ summary("NFC handover request from peer was already received - do not send own")
+ return
+
+ summary("Sending handover request")
+
+ handover.my_crn_ready = True
+
+ if not client.send_records(message):
+ handover.my_crn_ready = False
+ summary("Failed to send handover request", color=C_RED)
+ run_client_alt(handover, alt)
+ return
+
+ handover.my_crn, = struct.unpack('>H', crn)
+
+ summary("Receiving handover response")
+ try:
+ start = time.time()
+ message = client.recv_records(timeout=3.0)
+ end = time.time()
+ summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
+ except Exception as e:
+ # This is fine if we are the handover selector
+ if handover.hs_sent:
+ summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+ elif handover.alt_proposal_used and not alt:
+ summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
+ else:
+ summary("Client receive failed: %s" % str(e), color=C_RED)
+ message = None
+ if message is None:
+ if handover.hs_sent:
+ summary("No response received as expected since I'm the handover server")
+ elif handover.alt_proposal_used and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal was also used")
+ elif handover.try_own and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal will also be sent")
+ else:
+ summary("No response received", color=C_RED)
+ run_client_alt(handover, alt)
+ return
+ summary("Received message: " + str(message))
+ if len(message) < 1 or \
+ not isinstance(message[0], ndef.HandoverSelectRecord):
+ summary("Response was not Hs - received: " + message.type)
+ return
+
+ summary("Received handover select message")
+ summary("alternative carriers: " + str(message[0].alternative_carriers))
+ if handover.i_m_selector:
+ summary("Ignore the received select since I'm the handover selector")
+ run_client_alt(handover, alt)
+ return
+
+ if handover.alt_proposal_used and not alt:
+ summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
+ client.close()
+ return
+
+ dpp_found = False
+ for carrier in message:
+ if isinstance(carrier, ndef.HandoverSelectRecord):
+ continue
+ summary("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
+ continue
+ summary("DPP carrier type match - send to wpa_supplicant")
+ dpp_found = True
+ uri = carrier.data[1:].decode("utf-8")
+ summary("DPP URI: " + uri)
+ handover.peer_uri = uri
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ break
+ res = wpas_report_handover_sel(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover report rejected", color=C_RED)
+ break
+
+ success_report("DPP handover reported successfully (initiator)")
+ summary("peer_id=" + res)
+ peer_id = int(res)
+ wpas = wpas_connect()
+ if wpas is None:
+ break
+
+ global enrollee_only
+ global config_params
+ if enrollee_only:
+ extra = " role=enrollee"
+ elif config_params:
+ extra = " role=configurator " + config_params
+ else:
+ # TODO: Single Configurator instance
+ res = wpas.request("DPP_CONFIGURATOR_ADD")
+ if "FAIL" in res:
+ summary("Failed to initiate Configurator", color=C_RED)
+ break
+ conf_id = int(res)
+ extra = " conf=sta-dpp configurator=%d" % conf_id
+ global own_id
+ summary("Initiate DPP authentication")
+ cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id)
+ cmd += extra
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ summary("Failed to initiate DPP authentication", color=C_RED)
+ break
+
+ if not dpp_found and handover.no_alt_proposal:
+ summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
+ elif not dpp_found:
+ summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+ handover.alt_proposal = True
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ summary("Returning from dpp_handover_client")
+ return
+
+ summary("Remove peer")
+ handover.close()
+ summary("Done with handover")
+ global only_one
+ if only_one:
+ print("only_one -> stop loop")
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait or only_one:
+ summary("Trying to exit..")
+ global terminate_now
+ terminate_now = True
+
+ summary("Returning from dpp_handover_client")
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, handover, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+ self.llc = llc
+ self.handover = handover
+
+ def serve(self, socket):
+ peer_sap = socket.getpeername()
+ summary("Serving handover client on remote sap {0}".format(peer_sap))
+ send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
+ try:
+ while socket.poll("recv"):
+ req = bytearray()
+ while socket.poll("recv"):
+ r = socket.recv()
+ if r is None:
+ return None
+ summary("Received %d octets" % len(r))
+ req += r
+ if len(req) == 0:
+ continue
+ try:
+ list(ndef.message_decoder(req, 'strict', {}))
+ except ndef.DecodeError:
+ continue
+ summary("Full message received")
+ resp = self._process_request_data(req)
+ if resp is None or len(resp) == 0:
+ summary("No handover select to send out - wait for a possible alternative handover request")
+ handover.alt_proposal = True
+ req = bytearray()
+ continue
+
+ for offset in range(0, len(resp), send_miu):
+ if not socket.send(resp[offset:offset + send_miu]):
+ summary("Failed to send handover select - connection closed")
+ return
+ summary("Sent out full handover select")
+ if handover.terminate_on_hs_send_completion:
+ handover.delayed_exit()
+
+ except nfc.llcp.Error as e:
+ global terminate_now
+ summary("HandoverServer exception: %s" % e,
+ color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
+ finally:
+ socket.close()
+ summary("Handover serve thread exiting")
+
+ def process_handover_request_message(self, records):
+ handover = self.handover
+ self.ho_server_processing = True
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\n")
+ summary("HandoverServer - request received: " + str(records))
+
+ for carrier in records:
+ if not isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ if carrier.collision_resolution_number:
+ handover.peer_crn = carrier.collision_resolution_number
+ summary("peer_crn: %d" % handover.peer_crn)
+
+ if handover.my_crn is None and handover.my_crn_ready:
+ summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
+ for i in range(10):
+ if handover.my_crn is not None:
+ break
+ time.sleep(0.01)
+ if handover.my_crn is not None:
+ summary("my_crn: %d" % handover.my_crn)
+
+ if handover.my_crn is not None and handover.peer_crn is not None:
+ if handover.my_crn == handover.peer_crn:
+ summary("Same crn used - automatic collision resolution failed")
+ # TODO: Should generate a new Handover Request message
+ return ''
+ if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
+ handover.my_crn > handover.peer_crn) or \
+ ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
+ handover.my_crn < handover.peer_crn):
+ summary("I'm the Handover Selector Device")
+ handover.i_m_selector = True
+ else:
+ summary("Peer is the Handover Selector device")
+ summary("Ignore the received request.")
+ return ''
+
+ hs = ndef.HandoverSelectRecord('1.4')
+ sel = [hs]
+
+ found = False
+
+ for carrier in records:
+ if isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ summary("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ summary("DPP carrier type match - add DPP carrier record")
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
+ continue
+ uri = carrier.data[1:].decode("utf-8")
+ summary("Received DPP URI: " + uri)
+
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI")
+ data = test_sel_uri if test_sel_uri else test_uri
+ elif handover.alt_proposal and handover.altchanlist:
+ summary("Use alternative channel list while processing alternative proposal from peer")
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist,
+ pick_channel=True)
+ else:
+ data = wpas_get_nfc_uri(start_listen=False,
+ pick_channel=True)
+ summary("Own URI (pre-processing): %s" % data)
+
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ res = "OK"
+ data += " [%s]" % uri
+ else:
+ res = wpas_report_handover_req(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover request processing failed",
+ color=C_RED)
+ if handover.altchanlist:
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist)
+ summary("Own URI (try another channel list): %s" % data)
+ continue
+
+ if test_alt_uri:
+ summary("TEST MODE: Reject initial proposal")
+ continue
+
+ found = True
+
+ if not test_uri:
+ wpas = wpas_connect()
+ if wpas is None:
+ continue
+ global own_id
+ data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in data:
+ continue
+ summary("Own URI (post-processing): %s" % data)
+ handover.my_uri = data
+ handover.peer_uri = uri
+ uri = ndef.UriRecord(data)
+ summary("Own bootstrapping NFC URI record: " + str(uri))
+
+ if not test_uri:
+ info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+ freq = None
+ for line in info.splitlines():
+ if line.startswith("use_freq="):
+ freq = int(line.split('=')[1])
+ if freq is None or freq == 0:
+ summary("No channel negotiated over NFC - use channel 6")
+ freq = 2437
+ else:
+ summary("Negotiated channel: %d MHz" % freq)
+ if not dpp_start_listen(wpas, freq):
+ break
+
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ summary("Own DPP carrier record: " + str(carrier))
+ hs.add_alternative_carrier('active', carrier.name)
+ sel = [hs, carrier]
+ break
+
+ summary("Sending handover select: " + str(sel))
+ if found:
+ summary("Handover completed successfully")
+ handover.terminate_on_hs_send_completion = True
+ self.success = True
+ handover.hs_sent = True
+ handover.i_m_selector = True
+ elif handover.no_alt_proposal:
+ summary("Do not try alternative proposal anymore - handover failed",
+ color=C_RED)
+ handover.hs_sent = True
+ else:
+ summary("Try to initiate with alternative parameters")
+ handover.try_own = True
+ handover.hs_sent = False
+ handover.no_alt_proposal = True
+ if handover.client_thread:
+ handover.start_client_alt = True
+ else:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(self.llc, True))
+ handover.client_thread.start()
+ return sel
+
+def clear_raw_mode():
+ import sys, tty, termios
+ global prev_tcgetattr, in_raw_mode
+ if not in_raw_mode:
+ return
+ fd = sys.stdin.fileno()
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+
+def getch():
+ import sys, tty, termios, select
+ global prev_tcgetattr, in_raw_mode
+ fd = sys.stdin.fileno()
+ prev_tcgetattr = termios.tcgetattr(fd)
+ ch = None
+ try:
+ tty.setraw(fd)
+ in_raw_mode = True
+ [i, o, e] = select.select([fd], [], [], 0.05)
+ if i:
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+ return ch
+
+def dpp_tag_read(tag):
+ success = False
+ for record in tag.ndef.records:
+ summary(record)
+ summary("record type " + record.type)
+ if record.type == "application/vnd.wfa.dpp":
+ summary("DPP HS tag - send to wpa_supplicant")
+ success = dpp_hs_tag_read(record)
+ break
+ if isinstance(record, ndef.UriRecord):
+ summary("URI record: uri=" + record.uri)
+ summary("URI record: iri=" + record.iri)
+ if record.iri.startswith("DPP:"):
+ summary("DPP URI")
+ if not dpp_nfc_uri_process(record.iri):
+ break
+ success = True
+ else:
+ summary("Ignore unknown URI")
+ break
+
+ if success:
+ success_report("Tag read succeeded")
+
+ return success
+
+def rdwr_connected_write_tag(tag):
+ summary("Tag found - writing - " + str(tag))
+ if not tag.ndef:
+ summary("Not a formatted NDEF tag", color=C_RED)
+ return
+ if not tag.ndef.is_writeable:
+ summary("Not a writable tag", color=C_RED)
+ return
+ global dpp_tag_data
+ if tag.ndef.capacity < len(dpp_tag_data):
+ summary("Not enough room for the message")
+ return
+ try:
+ tag.ndef.records = dpp_tag_data
+ except ValueError as e:
+ summary("Writing the tag failed: %s" % str(e), color=C_RED)
+ return
+ success_report("Tag write succeeded")
+ summary("Tag writing completed - remove tag", color=C_GREEN)
+ global only_one, operation_success
+ operation_success = True
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global dpp_sel_wait_remove
+ return dpp_sel_wait_remove
+
+def write_nfc_uri(clf, wait_remove=True):
+ summary("Write NFC URI record")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ summary("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ summary(uri)
+
+ summary("Touch an NFC tag to write URI record", color=C_CYAN)
+ global dpp_tag_data
+ dpp_tag_data = [uri]
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def write_nfc_hs(clf, wait_remove=True):
+ summary("Write NFC Handover Select record on a tag")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ summary("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ summary(uri)
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hs = ndef.HandoverSelectRecord('1.4')
+ hs.add_alternative_carrier('active', carrier.name)
+ summary(hs)
+ summary(carrier)
+
+ summary("Touch an NFC tag to write HS record", color=C_CYAN)
+ global dpp_tag_data
+ dpp_tag_data = [hs, carrier]
+ summary(dpp_tag_data)
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ summary("NDEF tag: " + tag.type)
+ summary(tag.ndef.records)
+ success = dpp_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag", color=C_RED)
+ return True
+
+ return not no_wait
+
+def llcp_worker(llc, try_alt):
+ global handover
+ print("Start of llcp_worker()")
+ if try_alt:
+ summary("Starting handover client (try_alt)")
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (try_alt)")
+ return
+ global init_on_touch
+ if init_on_touch:
+ summary("Starting handover client (init_on_touch)")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (init_on_touch)")
+ return
+
+ global no_input
+ if no_input:
+ summary("Wait for handover to complete")
+ else:
+ print("Wait for handover to complete - press 'i' to initiate")
+ while not handover.wait_connection and handover.srv.sent_carrier is None:
+ if handover.try_own:
+ handover.try_own = False
+ summary("Try to initiate another handover with own parameters")
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (retry with own parameters)")
+ return
+ if handover.srv.ho_server_processing:
+ time.sleep(0.025)
+ elif no_input:
+ time.sleep(0.5)
+ else:
+ res = getch()
+ if res != 'i':
+ continue
+ clear_raw_mode()
+ summary("Starting handover client")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (manual init)")
+ return
+
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\r")
+ summary("Exiting llcp_worker thread")
+
+class ConnectionHandover():
+ def __init__(self):
+ self.client = None
+ self.client_thread = None
+ self.reset()
+ self.exit_thread = None
+
+ def reset(self):
+ self.wait_connection = False
+ self.my_crn_ready = False
+ self.my_crn = None
+ self.peer_crn = None
+ self.hs_sent = False
+ self.no_alt_proposal = False
+ self.alt_proposal_used = False
+ self.i_m_selector = False
+ self.start_client_alt = False
+ self.terminate_on_hs_send_completion = False
+ self.try_own = False
+ self.my_uri = None
+ self.peer_uri = None
+ self.connected = False
+ self.alt_proposal = False
+
+ def start_handover_server(self, llc):
+ summary("Start handover server")
+ self.llc = llc
+ self.srv = HandoverServer(self, llc)
+
+ def close(self):
+ if self.client:
+ self.client.close()
+ self.client = None
+
+ def run_delayed_exit(self):
+ summary("Trying to exit (delayed)..")
+ time.sleep(0.25)
+ summary("Trying to exit (after wait)..")
+ global terminate_now
+ terminate_now = True
+
+ def delayed_exit(self):
+ global only_one
+ if only_one:
+ self.exit_thread = threading.Thread(target=self.run_delayed_exit)
+ self.exit_thread.start()
+
+def llcp_startup(llc):
+ global handover
+ handover.start_handover_server(llc)
+ return llc
+
+def llcp_connected(llc):
+ summary("P2P LLCP connected")
+ global handover
+ handover.connected = True
+ handover.srv.start()
+ if init_on_touch or not no_input:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(llc, False))
+ handover.client_thread.start()
+ return True
+
+def llcp_release(llc):
+ summary("LLCP release")
+ global handover
+ handover.close()
+ return True
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--init-on-touch', '-I', action='store_true',
+ help='initiate handover on touch')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--ifname', '-i',
+ help='network interface name')
+ parser.add_argument('--no-input', '-a', action='store_true',
+ help='do not use stdout input to initiate handover')
+ parser.add_argument('--tag-read-only', '-t', action='store_true',
+ help='tag read only (do not allow connection handover)')
+ parser.add_argument('--handover-only', action='store_true',
+ help='connection handover only (do not allow tag read)')
+ parser.add_argument('--enrollee', action='store_true',
+ help='run as Enrollee-only')
+ parser.add_argument('--configurator', action='store_true',
+ help='run as Configurator-only')
+ parser.add_argument('--config-params', default='',
+ help='configurator parameters')
+ parser.add_argument('--ctrl', default='/var/run/wpa_supplicant',
+ help='wpa_supplicant/hostapd control interface')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('--device', default='usb', help='NFC device to open')
+ parser.add_argument('--chan', default=None, help='channel list')
+ parser.add_argument('--altchan', default=None, help='alternative channel list')
+ parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
+ parser.add_argument('--test-uri', default=None,
+ help='test mode: initial URI')
+ parser.add_argument('--test-alt-uri', default=None,
+ help='test mode: alternative URI')
+ parser.add_argument('--test-sel-uri', default=None,
+ help='test mode: handover select URI')
+ parser.add_argument('--test-crn', default=None,
+ help='test mode: hardcoded crn')
+ parser.add_argument('command', choices=['write-nfc-uri',
+ 'write-nfc-hs'],
+ nargs='?')
+ args = parser.parse_args()
+ summary(args)
+
+ global handover
+ handover = ConnectionHandover()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
+ global test_crn
+ chanlist = args.chan
+ handover.altchanlist = args.altchan
+ netrole = args.netrole
+ test_uri = args.test_uri
+ test_alt_uri = args.test_alt_uri
+ test_sel_uri = args.test_sel_uri
+ if args.test_crn:
+ test_crn = struct.pack('>H', int(args.test_crn))
+ else:
+ test_crn = None
+
+ logging.basicConfig(level=args.loglevel)
+ for l in ['nfc.clf.rcs380',
+ 'nfc.clf.transport',
+ 'nfc.clf.device',
+ 'nfc.clf.__init__',
+ 'nfc.llcp',
+ 'nfc.handover']:
+ log = logging.getLogger(l)
+ log.setLevel(args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ global enrollee_only
+ enrollee_only = args.enrollee
+
+ global configurator_only
+ configurator_only = args.configurator
+
+ global config_params
+ config_params = args.config_params
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ summary("Selected ifname " + ifname)
+
+ if args.ctrl:
+ global wpas_ctrl
+ wpas_ctrl = args.ctrl
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ if args.no_input:
+ global no_input
+ no_input = True
+
+ clf = nfc.ContactlessFrontend()
+
+ try:
+ if not clf.open(args.device):
+ summary("Could not open connection with an NFC device", color=C_RED)
+ raise SystemExit(1)
+
+ if args.command == "write-nfc-uri":
+ write_nfc_uri(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
+ raise SystemExit
+
+ if args.command == "write-nfc-hs":
+ write_nfc_hs(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ global in_raw_mode
+ was_in_raw_mode = in_raw_mode
+ clear_raw_mode()
+ if was_in_raw_mode:
+ print("\r")
+ if args.handover_only:
+ summary("Waiting a peer to be touched", color=C_MAGENTA)
+ elif args.tag_read_only:
+ summary("Waiting for a tag to be touched", color=C_BLUE)
+ else:
+ summary("Waiting for a tag or peer to be touched",
+ color=C_GREEN)
+ handover.wait_connection = True
+ try:
+ if args.tag_read_only:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+ break
+ elif args.handover_only:
+ if not clf.connect(llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ else:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ except Exception as e:
+ summary("clf.connect failed: " + str(e))
+ break
+
+ if only_one and handover.connected:
+ role = "selector" if handover.i_m_selector else "requestor"
+ summary("Connection handover result: I'm the %s" % role,
+ color=C_YELLOW)
+ if handover.peer_uri:
+ summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
+ if handover.my_uri:
+ summary("My URI: " + handover.my_uri, color=C_YELLOW)
+ if not (handover.peer_uri and handover.my_uri):
+ summary("Negotiated connection handover failed",
+ color=C_YELLOW)
+ break
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-action-udhcp.sh b/contrib/wpa/wpa_supplicant/examples/p2p-action-udhcp.sh
index d7d0e79b7bd2..53d8b777cd51 100755
--- a/contrib/wpa/wpa_supplicant/examples/p2p-action-udhcp.sh
+++ b/contrib/wpa/wpa_supplicant/examples/p2p-action-udhcp.sh
@@ -50,7 +50,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # enable NAT/masquarade $GIFNAME -> $UPLINK
+ # enable NAT/masquerade $GIFNAME -> $UPLINK
iptables -P FORWARD DROP
iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
@@ -61,7 +61,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # disable NAT/masquarade $GIFNAME -> $UPLINK
+ # disable NAT/masquerade $GIFNAME -> $UPLINK
sysctl net.ipv4.ip_forward=0
iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-action.sh b/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
index 797d43a0088a..6c27b27b787e 100755
--- a/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
+++ b/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
@@ -77,7 +77,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # enable NAT/masquarade $GIFNAME -> $UPLINK
+ # enable NAT/masquerade $GIFNAME -> $UPLINK
iptables -P FORWARD DROP
iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
@@ -88,7 +88,7 @@ fi
if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
GIFNAME=$3
UPLINK=$4
- # disable NAT/masquarade $GIFNAME -> $UPLINK
+ # disable NAT/masquerade $GIFNAME -> $UPLINK
sysctl net.ipv4.ip_forward=0
iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
index 6e3d94e20ca3..bfb553341ad6 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -71,7 +71,7 @@ class P2P_Connect():
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Dictionary of Arguements
+ # Dictionary of Arguments
global p2p_connect_arguements
# Constructor
@@ -108,7 +108,7 @@ class P2P_Connect():
self.path = None
try:
self.path = self.wpas.GetInterface(ifname)
- except:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceUnknown:"):
@@ -146,9 +146,9 @@ class P2P_Connect():
signal_name="WpsFailed")
- #Constructing all the arguements needed to connect
+ #Constructing all the arguments needed to connect
def constructArguements(self):
- # Adding required arguements
+ # Adding required arguments
self.p2p_connect_arguements = {'wps_method':self.wps_method,
'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
@@ -198,7 +198,7 @@ class P2P_Connect():
usage()
quit()
- # Go_intent is optional for all arguements
+ # Go_intent is optional for all arguments
if (self.go_intent != None):
self.p2p_connect_arguements.update(
{'go_intent':dbus.Int32(self.go_intent)})
@@ -239,7 +239,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -266,9 +266,9 @@ if __name__ == "__main__":
else:
assert False, "unhandled option"
- # Required Arguements check
+ # Required Arguments check
if (interface_name == None or wps_method == None or addr == None):
- print("Error:\n Required arguements not specified")
+ print("Error:\n Required arguments not specified")
usage()
quit()
@@ -289,7 +289,7 @@ if __name__ == "__main__":
addr,pin,wps_method,go_intent)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
index 85b5a8b39f5e..f04b98e667ce 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -125,7 +125,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
index e2df52896991..412d8120031a 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
@@ -136,7 +136,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
index 42fc7a3e915a..5cc3a0e18b23 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -125,7 +125,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
index 6d408218a25e..db6d60d80c1b 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -18,7 +18,7 @@ def usage():
print(" [-w <wpas_dbus_interface>]")
print("Options:")
print(" -i = interface name")
- print(" -p = persistant group = 0 (0=false, 1=true)")
+ print(" -p = persistent group = 0 (0=false, 1=true)")
print(" -f = frequency")
print(" -o = persistent group object path")
print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
@@ -57,7 +57,7 @@ class P2P_Group_Add (threading.Thread):
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Arguements
+ # Arguments
global P2PDictionary
# Constructor
@@ -120,7 +120,7 @@ class P2P_Group_Add (threading.Thread):
signal_name="WpsFailed")
# Sets up p2p_group_add dictionary
- def constructArguements(self):
+ def constructArguments(self):
self.P2PDictionary = {'persistent':self.persistent}
if (self.frequency != None):
@@ -141,7 +141,7 @@ class P2P_Group_Add (threading.Thread):
self.p2p_interface.GroupAdd(self.P2PDictionary)
except:
- print("Error:\n Could not preform group add")
+ print("Error:\n Could not perform group add")
usage()
os._exit(0)
@@ -172,7 +172,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -213,9 +213,9 @@ if __name__ == "__main__":
p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
persistent,frequency,persistent_group_object)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
- p2p_group_add_test.constructArguements()
+ p2p_group_add_test.constructArguments()
p2p_group_add_test.start()
time.sleep(5)
print("Error:\n Group formation timed out")
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
index 341dcd0a983d..8944e11ed47c 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -25,7 +25,7 @@ def usage():
# Required Signals
def InvitationResult(invite_result):
- print("Inviation Result signal :")
+ print("Invitation Result signal :")
status = invite_result['status']
print("status = ", status)
if invite_result.has_key('BSSID'):
@@ -55,7 +55,7 @@ class P2P_Invite (threading.Thread):
global wpas_dbus_interfaces_interface
global wpas_dbus_interfaces_p2pdevice
- # Arguements
+ # Arguments
global P2PDictionary
# Constructor
@@ -127,7 +127,7 @@ class P2P_Invite (threading.Thread):
self.p2p_interface.Invite(self.P2PDictionary)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
os._exit(0)
@@ -154,7 +154,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
@@ -190,7 +190,7 @@ if __name__ == "__main__":
P2P_Invite(interface_name,wpas_dbus_interface,
addr,persistent_group_object)
except:
- print("Error:\n Invalid Arguements")
+ print("Error:\n Invalid Arguments")
usage()
os._exit(1)
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
index b0837d9df5d2..cbeda9ff43ca 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -126,7 +126,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
index bdb4c0e3221d..f367196454d9 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -130,7 +130,7 @@ if __name__ == "__main__":
usage()
quit()
- # If theres a switch, override default option
+ # If there's a switch, override default option
for key, value in options:
# Help
if (key == "-h"):
diff --git a/contrib/wpa/wpa_supplicant/examples/udhcpd-p2p.conf b/contrib/wpa/wpa_supplicant/examples/udhcpd-p2p.conf
index df5909408a86..f92cc619e962 100644
--- a/contrib/wpa/wpa_supplicant/examples/udhcpd-p2p.conf
+++ b/contrib/wpa/wpa_supplicant/examples/udhcpd-p2p.conf
@@ -11,8 +11,8 @@ end 192.168.42.254 #default: 192.168.0.254
interface wlan2 #default: eth0
-# The maximim number of leases (includes addressesd reserved
-# by OFFER's, DECLINE's, and ARP conficts
+# The maximum number of leases (includes addresses reserved
+# by OFFER's, DECLINE's, and ARP conflicts)
#max_leases 254 #default: 254
@@ -52,12 +52,12 @@ interface wlan2 #default: eth0
# If a lease to be given is below this value, the full lease time is
# instead used (seconds).
-#min_lease 60 #defult: 60
+#min_lease 60 #default: 60
# The location of the leases file
-#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
+#lease_file /var/lib/misc/udhcpd.leases #default: /var/lib/misc/udhcpd.leases
# The location of the pid file
pidfile /var/run/udhcpd-wlan2.pid #default: /var/run/udhcpd.pid
@@ -77,7 +77,7 @@ pidfile /var/run/udhcpd-wlan2.pid #default: /var/run/udhcpd.pid
#boot_file /var/nfs_root #default: (none)
-# The remainer of options are DHCP options and can be specifed with the
+# The remainder of options are DHCP options and can be specified with the
# keyword 'opt' or 'option'. If an option can take multiple items, such
# as the dns option, they can be listed on the same line, or multiple
# lines. The only option with a default is 'lease'.
@@ -116,5 +116,3 @@ option lease 864000 # 10 days of seconds
# Static leases map
#static_lease 00:60:08:11:CE:4E 192.168.0.54
#static_lease 00:60:08:11:CE:3E 192.168.0.44
-
-
diff --git a/contrib/wpa/wpa_supplicant/gas_query.c b/contrib/wpa/wpa_supplicant/gas_query.c
index 8e977a3eccb3..e60a8c1fe6aa 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.c
+++ b/contrib/wpa/wpa_supplicant/gas_query.c
@@ -43,6 +43,7 @@ struct gas_query_pending {
unsigned int offchannel_tx_started:1;
unsigned int retry:1;
unsigned int wildcard_bssid:1;
+ unsigned int maintain_addr:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -693,12 +694,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
- if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Failed to assign random MAC address for GAS");
- gas_query_free(query, 1);
- radio_work_done(work);
- return;
+ if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
}
gas->work = work;
@@ -727,19 +731,24 @@ static void gas_query_tx_initial_req(struct gas_query *gas,
static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
{
- static int next_start = 0;
- int dialog_token;
-
- for (dialog_token = 0; dialog_token < 256; dialog_token++) {
- if (gas_query_dialog_token_available(
- gas, dst, (next_start + dialog_token) % 256))
+ u8 dialog_token;
+ int i;
+
+ /* There should never be more than couple active GAS queries in
+ * progress, so it should be very likely to find an available dialog
+ * token by checking random values. Use a limit on the number of
+ * iterations to handle the unexpected case of large number of pending
+ * queries cleanly. */
+ for (i = 0; i < 256; i++) {
+ /* Get a random number and check if the slot is available */
+ if (os_get_random(&dialog_token, sizeof(dialog_token)) < 0)
break;
+ if (gas_query_dialog_token_available(gas, dst, dialog_token))
+ return dialog_token;
}
- if (dialog_token == 256)
- return -1; /* Too many pending queries */
- dialog_token = (next_start + dialog_token) % 256;
- next_start = (dialog_token + 1) % 256;
- return dialog_token;
+
+ /* No dialog token value available */
+ return -1;
}
@@ -749,12 +758,23 @@ static int gas_query_set_sa(struct gas_query *gas,
struct wpa_supplicant *wpa_s = gas->wpa_s;
struct os_reltime now;
- if (!wpa_s->conf->gas_rand_mac_addr ||
+ if (query->maintain_addr ||
+ !wpa_s->conf->gas_rand_mac_addr ||
!(wpa_s->current_bss ?
(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
/* Use own MAC address as the transmitter address */
+ wpa_printf(MSG_DEBUG,
+ "GAS: Use own MAC address as the transmitter address%s%s%s",
+ query->maintain_addr ? " (maintain_addr)" : "",
+ !wpa_s->conf->gas_rand_mac_addr ? " (no gas_rand_mac_adr set)" : "",
+ !(wpa_s->current_bss ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA)) ?
+ " (no driver rand capa" : "");
os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
return 0;
}
@@ -800,6 +820,9 @@ static int gas_query_set_sa(struct gas_query *gas,
* @gas: GAS query data from gas_query_init()
* @dst: Destination MAC address for the query
* @freq: Frequency (in MHz) for the channel on which to send the query
+ * @wildcard_bssid: Force use of wildcard BSSID value
+ * @maintain_addr: Maintain own MAC address for exchange (i.e., ignore MAC
+ * address randomization rules)
* @req: GAS query payload (to be freed by gas_query module in case of success
* return)
* @cb: Callback function for reporting GAS query result and response
@@ -807,7 +830,7 @@ static int gas_query_set_sa(struct gas_query *gas,
* Returns: dialog token (>= 0) on success or -1 on failure
*/
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -829,6 +852,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
return -1;
query->gas = gas;
+ query->maintain_addr = !!maintain_addr;
if (gas_query_set_sa(gas, query)) {
os_free(query);
return -1;
diff --git a/contrib/wpa/wpa_supplicant/gas_query.h b/contrib/wpa/wpa_supplicant/gas_query.h
index d2b455442f0a..f9ce7b680fda 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.h
+++ b/contrib/wpa/wpa_supplicant/gas_query.h
@@ -35,7 +35,7 @@ enum gas_query_result {
};
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.c b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
index cb236df18d86..c1c823f2a85e 100644
--- a/contrib/wpa/wpa_supplicant/hs20_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
@@ -21,7 +21,7 @@
#include "config.h"
#include "scan.h"
#include "bss.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
@@ -288,7 +288,8 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, anqp_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -340,7 +341,7 @@ int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
{
struct icon_entry *icon;
size_t out_size;
- unsigned char *b64;
+ char *b64;
size_t b64_size;
int reply_size;
@@ -900,14 +901,25 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
/* OSU Friendly Name Duples */
while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
- if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
+ u8 slen;
+
+ slen = pos2[0];
+ if (1 + slen > pos - pos2) {
wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
break;
}
+ if (slen < 3) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid OSU Friendly Name (no room for language)");
+ break;
+ }
f = &prov->friendly_name[prov->friendly_name_count++];
- os_memcpy(f->lang, pos2 + 1, 3);
- os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
- pos2 += 1 + pos2[0];
+ pos2++;
+ os_memcpy(f->lang, pos2, 3);
+ pos2 += 3;
+ slen -= 3;
+ os_memcpy(f->text, pos2, slen);
+ pos2 += slen;
}
/* OSU Server URI */
@@ -1287,8 +1299,8 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
code, reauth_delay, url);
if (code == HS20_DEAUTH_REASON_CODE_BSS) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist");
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to ignore list");
+ wpa_bssid_ignore_add(wpa_s, wpa_s->bssid);
/* TODO: For now, disable full ESS since some drivers may not
* support disabling per BSS. */
if (wpa_s->current_ssid) {
diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.c b/contrib/wpa/wpa_supplicant/ibss_rsn.c
index 6934c4725da3..02e63904c5d7 100644
--- a/contrib/wpa/wpa_supplicant/ibss_rsn.c
+++ b/contrib/wpa/wpa_supplicant/ibss_rsn.c
@@ -64,10 +64,16 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
{
struct ibss_rsn_peer *peer = ctx;
struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+ int encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK;
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
+ wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR
+ " proto=0x%04x len=%lu no_encrypt=%d)",
+ __func__, MAC2STR(dest), proto, (unsigned long) len,
+ !encrypt);
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
@@ -111,6 +117,7 @@ static int supp_get_beacon_ie(void *ctx)
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */
+ wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
@@ -139,7 +146,7 @@ static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
static int supp_set_key(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
struct ibss_rsn_peer *peer = ctx;
@@ -166,7 +173,7 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
if (is_broadcast_ether_addr(addr))
addr = peer->addr;
return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
+ set_tx, seq, seq_len, key, key_len, key_flag);
}
@@ -193,7 +200,13 @@ static void supp_cancel_auth_timeout(void *ctx)
}
-static void supp_deauthenticate(void * ctx, u16 reason_code)
+static void supp_deauthenticate(void *ctx, u16 reason_code)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static void supp_reconnect(void *ctx)
{
wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
}
@@ -218,6 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
ctx->mlme_setprotection = supp_mlme_setprotection;
ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
ctx->deauthenticate = supp_deauthenticate;
+ ctx->reconnect = supp_reconnect;
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
@@ -286,6 +300,10 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
"encrypt=%d)",
__func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
data_len);
@@ -295,7 +313,8 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct ibss_rsn *ibss_rsn = ctx;
u8 seq[6];
@@ -334,7 +353,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
}
return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -464,7 +483,7 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
@@ -486,9 +505,6 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
- if (wpa_s->driver->send_frame == NULL)
- return -1;
-
os_memset(&auth, 0, sizeof(auth));
auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -504,8 +520,7 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
seq, MAC2STR(da));
- return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
- auth_length, 0);
+ return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0);
}
@@ -851,7 +866,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
MACSTR, MAC2STR(addr));
wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
- NULL, 0, NULL, 0);
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
if (peer &&
diff --git a/contrib/wpa/wpa_supplicant/interworking.c b/contrib/wpa/wpa_supplicant/interworking.c
index dd35571d914b..1c82d2117ab0 100644
--- a/contrib/wpa/wpa_supplicant/interworking.c
+++ b/contrib/wpa/wpa_supplicant/interworking.c
@@ -176,7 +176,7 @@ static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
continue;
if (!cred->eap_method)
return 1;
- if (cred->realm && cred->roaming_consortium_len == 0)
+ if (cred->realm)
return 1;
}
return 0;
@@ -316,7 +316,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
+ res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, 0, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -946,7 +946,8 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
struct wpa_driver_capa capa;
res = wpa_drv_get_capa(wpa_s, &capa);
- if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ if (res == 0 && capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT) {
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256 FT-EAP" :
"WPA-EAP FT-EAP";
@@ -958,7 +959,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
- wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w",
+ wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_REQUIRED ?
+ "2" : "1", 0) < 0 ||
wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -1395,7 +1398,11 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
!roaming_consortium_match(ie, anqp,
cred->roaming_consortium,
cred->roaming_consortium_len)) &&
- !cred_roaming_consortiums_match(ie, anqp, cred))
+ !cred_roaming_consortiums_match(ie, anqp, cred) &&
+ (cred->required_roaming_consortium_len == 0 ||
+ !roaming_consortium_match(
+ ie, anqp, cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len)))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1550,7 +1557,7 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
cred->domain_suffix_match) < 0)
return -1;
- ssid->eap.ocsp = cred->ocsp;
+ ssid->eap.cert.ocsp = cred->ocsp;
return 0;
}
@@ -2258,7 +2265,7 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
realm++;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Search for match with SIM/USIM domain %s",
- realm);
+ realm ? realm : "[NULL]");
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
@@ -2475,7 +2482,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
- excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP,
+ excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP,
MAC2STR(bss->bssid), type,
bh ? " below_min_backhaul=1" : "",
bss_load ? " over_max_bss_load=1" : "",
@@ -2525,7 +2532,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
(selected_cred == NULL ||
cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) {
/* Prefer network operated by the Home SP */
- wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home");
+ wpa_printf(MSG_DEBUG, "Interworking: Overrode selected with selected_home");
selected = selected_home;
selected_cred = selected_home_cred;
}
@@ -2743,27 +2750,27 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
}
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes)
{
struct wpabuf *buf;
struct wpabuf *extra_buf = NULL;
int ret = 0;
- int freq;
struct wpa_bss *bss;
int res;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (!bss) {
+ if (!bss && !freq) {
wpa_printf(MSG_WARNING,
- "ANQP: Cannot send query to unknown BSS "
- MACSTR, MAC2STR(dst));
+ "ANQP: Cannot send query without BSS freq info");
return -1;
}
- wpa_bss_anqp_unshare_alloc(bss);
- freq = bss->freq;
+ if (bss)
+ wpa_bss_anqp_unshare_alloc(bss);
+ if (bss && !freq)
+ freq = bss->freq;
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Query Request to " MACSTR " for %u id(s)",
@@ -2782,6 +2789,14 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (mbo_subtypes) {
struct wpabuf *mbo;
+ if (!bss) {
+ wpa_printf(MSG_WARNING,
+ "ANQP: Cannot send MBO query to unknown BSS "
+ MACSTR, MAC2STR(dst));
+ wpabuf_free(extra_buf);
+ return -1;
+ }
+
mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
if (mbo) {
if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
@@ -2800,7 +2815,8 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, anqp_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -2816,7 +2832,7 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
static void anqp_add_extra(struct wpa_supplicant *wpa_s,
struct wpa_bss_anqp *anqp, u16 info_id,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen, bool protected_response)
{
struct wpa_bss_anqp_elem *tmp, *elem = NULL;
@@ -2841,6 +2857,7 @@ static void anqp_add_extra(struct wpa_supplicant *wpa_s,
wpabuf_free(elem->payload);
}
+ elem->protected_response = protected_response;
elem->payload = wpabuf_alloc_copy(data, slen);
if (!elem->payload) {
dl_list_del(&elem->list);
@@ -2883,6 +2900,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
const u8 *pos = data;
struct wpa_bss_anqp *anqp = NULL;
u8 type;
+ bool protected_response;
if (bss)
anqp = bss->anqp;
@@ -2983,9 +3001,11 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
case ANQP_VENUE_URL:
wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
MAC2STR(sa));
- anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
+ protected_response = pmf_in_use(wpa_s, sa);
+ anqp_add_extra(wpa_s, anqp, info_id, pos, slen,
+ protected_response);
- if (!pmf_in_use(wpa_s, sa)) {
+ if (!protected_response) {
wpa_printf(MSG_DEBUG,
"ANQP: Ignore Venue URL since PMF was not enabled");
break;
@@ -3037,7 +3057,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
default:
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported ANQP Info ID %u", info_id);
- anqp_add_extra(wpa_s, anqp, info_id, data, slen);
+ anqp_add_extra(wpa_s, anqp, info_id, data, slen,
+ pmf_in_use(wpa_s, sa));
break;
}
}
@@ -3239,7 +3260,8 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
} else
wpabuf_put_le16(buf, 0);
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, gas_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
diff --git a/contrib/wpa/wpa_supplicant/interworking.h b/contrib/wpa/wpa_supplicant/interworking.h
index 37ee2e904e48..77b2c91bda52 100644
--- a/contrib/wpa/wpa_supplicant/interworking.h
+++ b/contrib/wpa/wpa_supplicant/interworking.h
@@ -11,7 +11,7 @@
enum gas_query_result;
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
diff --git a/contrib/wpa/wpa_supplicant/main.c b/contrib/wpa/wpa_supplicant/main.c
index 745eebe71d7d..7ab3a60442a5 100644
--- a/contrib/wpa/wpa_supplicant/main.c
+++ b/contrib/wpa/wpa_supplicant/main.c
@@ -66,7 +66,7 @@ static void usage(void)
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
" -d = increase debugging verbosity (-dd even more)\n"
- " -D = driver name (can be multiple drivers: nl80211,wext)\n"
+ " -D = driver name (can be multiple drivers: bsd,wired)\n"
" -e = entropy file\n"
#ifdef CONFIG_DEBUG_FILE
" -f = log output to debug file instead of stdout\n"
@@ -105,8 +105,7 @@ static void usage(void)
" -W = wait for a control interface monitor before starting\n");
printf("example:\n"
- " wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
- wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211");
+ " wpa_supplicant -Dbsd -iwlan0 -c/etc/wpa_supplicant.conf\n");
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -199,11 +198,6 @@ int main(int argc, char *argv[])
wpa_supplicant_fd_workaround(1);
-#ifdef CONFIG_DRIVER_NDIS
- void driver_ndis_init_ops(void);
- driver_ndis_init_ops();
-#endif /* CONFIG_DRIVER_NDIS */
-
for (;;) {
c = getopt(argc, argv,
"b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
diff --git a/contrib/wpa/wpa_supplicant/main_winmain.c b/contrib/wpa/wpa_supplicant/main_winmain.c
new file mode 100644
index 000000000000..e1dded0c349a
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/main_winmain.c
@@ -0,0 +1,78 @@
+/*
+ * WPA Supplicant / WinMain() function for Windows-based applications
+ * Copyright (c) 2006, 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 "wpa_supplicant_i.h"
+
+#ifdef _WIN32_WCE
+#define CMDLINE LPWSTR
+#else /* _WIN32_WCE */
+#define CMDLINE LPSTR
+#endif /* _WIN32_WCE */
+
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ CMDLINE lpCmdLine, int nShowCmd)
+{
+ int i;
+ struct wpa_interface *ifaces, *iface;
+ int iface_count, exitcode = -1;
+ struct wpa_params params;
+ struct wpa_global *global;
+
+ if (os_program_init())
+ return -1;
+
+ os_memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_MSGDUMP;
+ params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+ params.wpa_debug_show_keys = 1;
+
+ iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
+ if (ifaces == NULL)
+ return -1;
+ iface_count = 1;
+
+ iface->confname = "default";
+ iface->driver = "ndis";
+ iface->ifname = "";
+
+ exitcode = 0;
+ global = wpa_supplicant_init(&params);
+ if (global == NULL) {
+ printf("Failed to initialize wpa_supplicant\n");
+ exitcode = -1;
+ }
+
+ for (i = 0; exitcode == 0 && i < iface_count; i++) {
+ if ((ifaces[i].confname == NULL &&
+ ifaces[i].ctrl_interface == NULL) ||
+ ifaces[i].ifname == NULL) {
+ if (iface_count == 1 && (params.ctrl_interface ||
+ params.dbus_ctrl_interface))
+ break;
+ exitcode = -1;
+ break;
+ }
+ if (wpa_supplicant_add_iface(global, &ifaces[i], NULL) == NULL)
+ exitcode = -1;
+ }
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ os_free(ifaces);
+
+ os_program_deinit();
+
+ return exitcode;
+}
diff --git a/contrib/wpa/wpa_supplicant/main_winsvc.c b/contrib/wpa/wpa_supplicant/main_winsvc.c
new file mode 100644
index 000000000000..9950aa99ae7a
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/main_winsvc.c
@@ -0,0 +1,458 @@
+/*
+ * WPA Supplicant / main() function for Win32 service
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * The root of wpa_supplicant configuration in registry is
+ * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
+ * parameters and a 'interfaces' subkey with all the interface configuration
+ * (adapter to confname mapping). Each such mapping is a subkey that has
+ * 'adapter' and 'config' values.
+ *
+ * This program can be run either as a normal command line application, e.g.,
+ * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need
+ * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After
+ * this, it can be started like any other Windows service (e.g., 'net start
+ * wpasvc') or it can be configured to start automatically through the Services
+ * tool in administrative tasks. The service can be unregistered with
+ * 'wpasvc.exe unreg'.
+ */
+
+#include "includes.h"
+#include <windows.h>
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "eloop.h"
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+#ifndef WPASVC_DISPLAY_NAME
+#define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service")
+#endif
+#ifndef WPASVC_DESCRIPTION
+#define WPASVC_DESCRIPTION \
+TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality")
+#endif
+
+static HANDLE kill_svc;
+
+static SERVICE_STATUS_HANDLE svc_status_handle;
+static SERVICE_STATUS svc_status;
+
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int read_interface(struct wpa_global *global, HKEY _hk,
+ const TCHAR *name)
+{
+ HKEY hk;
+#define TBUFLEN 255
+ TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
+ DWORD buflen, val;
+ LONG ret;
+ struct wpa_interface iface;
+ int skip_on_error = 0;
+
+ ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant interface key\n");
+ return -1;
+ }
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.driver = "ndis";
+
+ buflen = sizeof(ctrl_interface);
+ ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
+ (LPBYTE) ctrl_interface, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ ctrl_interface[TBUFLEN - 1] = TEXT('\0');
+ wpa_unicode2ascii_inplace(ctrl_interface);
+ printf("ctrl_interface[len=%d] '%s'\n",
+ (int) buflen, (char *) ctrl_interface);
+ iface.ctrl_interface = (char *) ctrl_interface;
+ }
+
+ buflen = sizeof(adapter);
+ ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
+ (LPBYTE) adapter, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ adapter[TBUFLEN - 1] = TEXT('\0');
+ wpa_unicode2ascii_inplace(adapter);
+ printf("adapter[len=%d] '%s'\n",
+ (int) buflen, (char *) adapter);
+ iface.ifname = (char *) adapter;
+ }
+
+ buflen = sizeof(config);
+ ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
+ (LPBYTE) config, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ config[sizeof(config) - 1] = '\0';
+ wpa_unicode2ascii_inplace(config);
+ printf("config[len=%d] '%s'\n",
+ (int) buflen, (char *) config);
+ iface.confname = (char *) config;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val))
+ skip_on_error = val;
+
+ RegCloseKey(hk);
+
+ if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL) {
+ if (skip_on_error)
+ wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
+ "initialization failure", iface.ifname);
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_thread(void)
+{
+ int exitcode;
+ struct wpa_params params;
+ struct wpa_global *global;
+ HKEY hk, ihk;
+ DWORD val, buflen, i;
+ LONG ret;
+
+ if (os_program_init())
+ return -1;
+
+ os_memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
+ 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant registry key\n");
+ return -1;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_level = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_show_keys = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_timestamp = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
+ params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+ }
+
+ exitcode = 0;
+ global = wpa_supplicant_init(&params);
+ if (global == NULL) {
+ printf("Failed to initialize wpa_supplicant\n");
+ exitcode = -1;
+ }
+
+ ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
+ &ihk);
+ RegCloseKey(hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant interfaces registry "
+ "key\n");
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ printf("RegEnumKeyEx failed: 0x%x\n",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+ wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
+ if (read_interface(global, ihk, name) < 0)
+ exitcode = -1;
+ }
+
+ RegCloseKey(ihk);
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ os_program_deinit();
+
+ return exitcode;
+}
+
+
+static DWORD svc_thread(LPDWORD param)
+{
+ int ret = wpa_supplicant_thread();
+
+ svc_status.dwCurrentState = SERVICE_STOPPED;
+ svc_status.dwWaitHint = 0;
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ }
+
+ return ret;
+}
+
+
+static int register_service(const TCHAR *exe)
+{
+ SC_HANDLE svc, scm;
+ SERVICE_DESCRIPTION sd;
+
+ printf("Registering service: " TSTR "\n", WPASVC_NAME);
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+ if (!scm) {
+ printf("OpenSCManager failed: %d\n", (int) GetLastError());
+ return -1;
+ }
+
+ svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
+ SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
+ exe, NULL, NULL, NULL, NULL, NULL);
+
+ if (!svc) {
+ printf("CreateService failed: %d\n\n", (int) GetLastError());
+ CloseServiceHandle(scm);
+ return -1;
+ }
+
+ os_memset(&sd, 0, sizeof(sd));
+ sd.lpDescription = WPASVC_DESCRIPTION;
+ if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
+ printf("ChangeServiceConfig2 failed: %d\n",
+ (int) GetLastError());
+ /* This is not a fatal error, so continue anyway. */
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+
+ printf("Service registered successfully.\n");
+
+ return 0;
+}
+
+
+static int unregister_service(void)
+{
+ SC_HANDLE svc, scm;
+ SERVICE_STATUS status;
+
+ printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+ if (!scm) {
+ printf("OpenSCManager failed: %d\n", (int) GetLastError());
+ return -1;
+ }
+
+ svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
+ if (!svc) {
+ printf("OpenService failed: %d\n\n", (int) GetLastError());
+ CloseServiceHandle(scm);
+ return -1;
+ }
+
+ if (QueryServiceStatus(svc, &status)) {
+ if (status.dwCurrentState != SERVICE_STOPPED) {
+ printf("Service currently active - stopping "
+ "service...\n");
+ if (!ControlService(svc, SERVICE_CONTROL_STOP,
+ &status)) {
+ printf("ControlService failed: %d\n",
+ (int) GetLastError());
+ }
+ Sleep(500);
+ }
+ }
+
+ if (DeleteService(svc)) {
+ printf("Service unregistered successfully.\n");
+ } else {
+ printf("DeleteService failed: %d\n", (int) GetLastError());
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+
+ return 0;
+}
+
+
+static void WINAPI service_ctrl_handler(DWORD control_code)
+{
+ switch (control_code) {
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ svc_status.dwCurrentState = SERVICE_STOP_PENDING;
+ svc_status.dwWaitHint = 2000;
+ eloop_terminate();
+ SetEvent(kill_svc);
+ break;
+ }
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ }
+}
+
+
+static void WINAPI service_start(DWORD argc, LPTSTR *argv)
+{
+ DWORD id;
+
+ svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
+ service_ctrl_handler);
+ if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
+ printf("RegisterServiceCtrlHandler failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ os_memset(&svc_status, 0, sizeof(svc_status));
+ svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ svc_status.dwCurrentState = SERVICE_START_PENDING;
+ svc_status.dwWaitHint = 1000;
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ kill_svc = CreateEvent(0, TRUE, FALSE, 0);
+ if (!kill_svc) {
+ printf("CreateEvent failed: %d\n", (int) GetLastError());
+ return;
+ }
+
+ if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
+ == 0) {
+ printf("CreateThread failed: %d\n", (int) GetLastError());
+ return;
+ }
+
+ if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
+ svc_status.dwCurrentState = SERVICE_RUNNING;
+ svc_status.dwWaitHint = 0;
+ svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_SHUTDOWN;
+ }
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ /* wait until service gets killed */
+ WaitForSingleObject(kill_svc, INFINITE);
+}
+
+
+int main(int argc, char *argv[])
+{
+ SERVICE_TABLE_ENTRY dt[] = {
+ { WPASVC_NAME, service_start },
+ { NULL, NULL }
+ };
+
+ if (argc > 1) {
+ if (os_strcmp(argv[1], "reg") == 0) {
+ TCHAR *path;
+ int ret;
+
+ if (argc < 3) {
+ path = os_malloc(MAX_PATH * sizeof(TCHAR));
+ if (path == NULL)
+ return -1;
+ if (!GetModuleFileName(NULL, path, MAX_PATH)) {
+ printf("GetModuleFileName failed: "
+ "%d\n", (int) GetLastError());
+ os_free(path);
+ return -1;
+ }
+ } else {
+ path = wpa_strdup_tchar(argv[2]);
+ if (path == NULL)
+ return -1;
+ }
+ ret = register_service(path);
+ os_free(path);
+ return ret;
+ } else if (os_strcmp(argv[1], "unreg") == 0) {
+ return unregister_service();
+ } else if (os_strcmp(argv[1], "app") == 0) {
+ return wpa_supplicant_thread();
+ }
+ }
+
+ if (!StartServiceCtrlDispatcher(dt)) {
+ printf("StartServiceCtrlDispatcher failed: %d\n",
+ (int) GetLastError());
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/mbo.c b/contrib/wpa/wpa_supplicant/mbo.c
index 43b1fa7beb38..3df86ef0724e 100644
--- a/contrib/wpa/wpa_supplicant/mbo.c
+++ b/contrib/wpa/wpa_supplicant/mbo.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -82,6 +83,35 @@ const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
}
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid)
+{
+ const u8 *rsne, *mbo, *oce;
+ struct wpa_ie_data ie;
+
+ wpa_s->disable_mbo_oce = 0;
+ if (!bss)
+ return;
+ mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
+ oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
+ if (!mbo && !oce)
+ return;
+ if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
+ return; /* STA-CFON is not required to enable PMF */
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
+ return; /* AP is not using RSN */
+
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
+ wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
+ wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
+ if (wpa_s->disable_mbo_oce)
+ wpa_printf(MSG_INFO,
+ "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
+}
+
+
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo,
u8 start, u8 end)
diff --git a/contrib/wpa/wpa_supplicant/mesh.c b/contrib/wpa/wpa_supplicant/mesh.c
index 7354c1b79161..901b49b4d257 100644
--- a/contrib/wpa/wpa_supplicant/mesh.c
+++ b/contrib/wpa/wpa_supplicant/mesh.c
@@ -13,6 +13,7 @@
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "ap/sta_info.h"
#include "ap/hostapd.h"
#include "ap/ieee802_11.h"
@@ -27,22 +28,30 @@
#include "mesh.h"
-static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s,
+ bool also_clear_hostapd)
{
- wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
- wpa_s->ifmsh = NULL;
- wpa_s->current_ssid = NULL;
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh,
+ also_clear_hostapd);
+
+ if (also_clear_hostapd) {
+ wpa_s->ifmsh = NULL;
+ wpa_s->current_ssid = NULL;
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = NULL;
+ }
+
os_free(wpa_s->mesh_rsn);
wpa_s->mesh_rsn = NULL;
- os_free(wpa_s->mesh_params);
- wpa_s->mesh_params = NULL;
- /* TODO: leave mesh (stop beacon). This will happen on link down
- * anyway, so it's not urgent */
+
+ if (!also_clear_hostapd)
+ wpa_supplicant_leave_mesh(wpa_s, false);
}
void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
- struct hostapd_iface *ifmsh)
+ struct hostapd_iface *ifmsh,
+ bool also_clear_hostapd)
{
if (!ifmsh)
return;
@@ -63,8 +72,10 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
}
/* take care of shared data */
- hostapd_interface_deinit(ifmsh);
- hostapd_interface_free(ifmsh);
+ if (also_clear_hostapd) {
+ hostapd_interface_deinit(ifmsh);
+ hostapd_interface_free(ifmsh);
+ }
}
@@ -86,7 +97,6 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
-#ifdef CONFIG_IEEE80211W
conf->ieee80211w = ssid->ieee80211w;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
@@ -94,7 +104,6 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
else
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf->ocv = ssid->ocv;
#endif /* CONFIG_OCV */
@@ -116,8 +125,14 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
}
conf->group_cipher = cipher;
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
- conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256)
+ conf->mgmt_group_cipher = ssid->group_mgmt_cipher;
+ else
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ }
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -190,6 +205,40 @@ static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
}
+static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct he_capabilities *he_capab = NULL;
+
+ if (ifmsh->current_mode)
+ he_capab = &ifmsh->current_mode->he_capab[IEEE80211_MODE_MESH];
+
+ if (hostapd_set_freq_params(
+ &params->freq,
+ ifmsh->conf->hw_mode,
+ ifmsh->freq,
+ ifmsh->conf->channel,
+ ifmsh->conf->enable_edmg,
+ ifmsh->conf->edmg_channel,
+ ifmsh->conf->ieee80211n,
+ ifmsh->conf->ieee80211ac,
+ ifmsh->conf->ieee80211ax,
+ ifmsh->conf->secondary_channel,
+ hostapd_get_oper_chwidth(ifmsh->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
+ ifmsh->conf->vht_capab,
+ he_capab)) {
+ wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
+ wpa_supplicant_mesh_deinit(wpa_s, true);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
{
struct hostapd_iface *ifmsh = wpa_s->ifmsh;
@@ -203,12 +252,22 @@ static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
return -1;
}
+ /*
+ * Update channel configuration if the channel has changed since the
+ * initial setting, i.e., due to DFS radar detection during CAC.
+ */
+ if (ifmsh->freq > 0 && ifmsh->freq != params->freq.freq) {
+ wpa_s->assoc_freq = ifmsh->freq;
+ ssid->frequency = ifmsh->freq;
+ if (wpas_mesh_update_freq_params(wpa_s) < 0)
+ return -1;
+ }
+
if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
wpas_mesh_init_rsn(wpa_s)) {
wpa_printf(MSG_ERROR,
"mesh: RSN initialization failed - deinit mesh");
- wpa_supplicant_mesh_deinit(wpa_s);
- wpa_drv_leave_mesh(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, false);
return -1;
}
@@ -233,13 +292,90 @@ static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
/* hostapd sets the interface down until we associate */
wpa_drv_set_operstate(wpa_s, 1);
- if (!ret)
+ if (!ret) {
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
+ wpas_notify_mesh_group_started(wpa_s, ssid);
+ }
+
return ret;
}
+static void wpas_mesh_complete_cb(void *arg)
+{
+ struct wpa_supplicant *wpa_s = arg;
+
+ wpas_mesh_complete(wpa_s);
+}
+
+
+static int wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface *ifmsh)
+{
+ struct wpa_supplicant *wpa_s = ifmsh->owner;
+ struct hostapd_data *bss;
+
+ ifmsh->mconf = mesh_config_create(wpa_s, wpa_s->current_ssid);
+
+ bss = ifmsh->bss[0];
+ bss->msg_ctx = wpa_s;
+ os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+ bss->driver = wpa_s->driver;
+ bss->drv_priv = wpa_s->drv_priv;
+ bss->iface = ifmsh;
+ bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+ bss->setup_complete_cb = wpas_mesh_complete_cb;
+ bss->setup_complete_cb_ctx = wpa_s;
+
+ bss->conf->start_disabled = 1;
+ bss->conf->mesh = MESH_ENABLED;
+ bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+ if (wpa_drv_init_mesh(wpa_s)) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
+ return -1;
+ }
+
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface *ifmsh)
+{
+ struct wpa_supplicant *wpa_s = ifmsh->owner;
+ size_t j;
+
+ wpa_supplicant_mesh_deinit(wpa_s, false);
+
+#ifdef NEED_AP_MLME
+ for (j = 0; j < ifmsh->num_bss; j++)
+ hostapd_cleanup_cs_params(ifmsh->bss[j]);
+#endif /* NEED_AP_MLME */
+
+ /* Same as hostapd_interface_deinit() without deinitializing control
+ * interface */
+ for (j = 0; j < ifmsh->num_bss; j++) {
+ struct hostapd_data *hapd = ifmsh->bss[j];
+
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_free_hapd_data(hapd);
+ }
+
+ hostapd_cleanup_iface_partial(ifmsh);
+
+ return 0;
+}
+
+
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -263,8 +399,12 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
if (!ifmsh)
return -ENOMEM;
+ ifmsh->owner = wpa_s;
ifmsh->drv_flags = wpa_s->drv_flags;
+ ifmsh->drv_flags2 = wpa_s->drv_flags2;
ifmsh->num_bss = 1;
+ ifmsh->enable_iface_cb = wpa_supplicant_mesh_enable_iface_cb;
+ ifmsh->disable_iface_cb = wpa_supplicant_mesh_disable_iface_cb;
ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
sizeof(struct hostapd_data *));
if (!ifmsh->bss)
@@ -280,11 +420,14 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
bss->drv_priv = wpa_s->drv_priv;
bss->iface = ifmsh;
bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+ bss->setup_complete_cb = wpas_mesh_complete_cb;
+ bss->setup_complete_cb_ctx = wpa_s;
frequency = ssid->frequency;
if (frequency != freq->freq &&
frequency == freq->freq + freq->sec_channel_offset * 20) {
wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
frequency = freq->freq;
+ ssid->frequency = frequency;
}
wpa_s->assoc_freq = frequency;
wpa_s->current_ssid = ssid;
@@ -306,6 +449,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
conf->country[0] = wpa_s->conf->country[0];
conf->country[1] = wpa_s->conf->country[1];
conf->country[2] = ' ';
+ wpa_s->mesh_params->handle_dfs = true;
}
bss->iconf = conf;
@@ -328,30 +472,6 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
frequency);
goto out_free;
}
- if (ssid->ht40)
- conf->secondary_channel = ssid->ht40;
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
- if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
- switch (conf->vht_oper_chwidth) {
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_80P80MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- break;
- case CHANWIDTH_160MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
- break;
- }
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
- }
if (ssid->mesh_basic_rates == NULL) {
/*
@@ -382,6 +502,31 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
conf->basic_rates[rate_len] = -1;
}
+ /* While it can enhance performance to switch the primary channel, which
+ * is also the secondary channel of another network at the same time),
+ * to the other primary channel, problems exist with this in mesh
+ * networks.
+ *
+ * Example with problems:
+ * - 3 mesh nodes M1-M3, freq (5200, 5180)
+ * - other node O1, e.g. AP mode, freq (5180, 5200),
+ * Locations: O1 M1 M2 M3
+ *
+ * M3 can only send frames to M1 over M2, no direct connection is
+ * possible
+ * Start O1, M1 and M3 first, M1 or O1 will switch channels to align
+ * with* each other. M3 does not swap, because M1 or O1 cannot be
+ * reached. M2 is started afterwards and can either connect to M3 or M1
+ * because of this primary secondary channel switch.
+ *
+ * Solutions: (1) central coordination -> not always possible
+ * (2) disable pri/sec channel switch in mesh networks
+ *
+ * In AP mode, when all nodes can work independently, this poses of
+ * course no problem, therefore disable it only in mesh mode. */
+ conf->no_pri_sec_switch = 1;
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
@@ -393,11 +538,9 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
return -1;
}
- wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
-
return 0;
out_free:
- wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, true);
return -ENOMEM;
}
@@ -445,7 +588,7 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
goto out;
}
- wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_supplicant_mesh_deinit(wpa_s, true);
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
@@ -516,25 +659,25 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
wpa_s->mesh_params = params;
if (wpa_supplicant_mesh_init(wpa_s, ssid, &params->freq)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
- wpa_drv_leave_mesh(wpa_s);
+ wpa_supplicant_leave_mesh(wpa_s, true);
ret = -1;
goto out;
}
- ret = wpas_mesh_complete(wpa_s);
out:
return ret;
}
-int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s, bool need_deinit)
{
int ret = 0;
wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
/* Need to send peering close messages first */
- wpa_supplicant_mesh_deinit(wpa_s);
+ if (need_deinit)
+ wpa_supplicant_mesh_deinit(wpa_s, true);
ret = wpa_drv_leave_mesh(wpa_s);
if (ret)
diff --git a/contrib/wpa/wpa_supplicant/mesh.h b/contrib/wpa/wpa_supplicant/mesh.h
index 7317083c99cd..a429e5e27358 100644
--- a/contrib/wpa/wpa_supplicant/mesh.h
+++ b/contrib/wpa/wpa_supplicant/mesh.h
@@ -11,9 +11,11 @@
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
-int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s,
+ bool need_deinit);
void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
- struct hostapd_iface *ifmsh);
+ struct hostapd_iface *ifmsh,
+ bool also_clear_hostapd);
int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
char *end);
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.c b/contrib/wpa/wpa_supplicant/mesh_mpm.c
index 4a163b6eb6d8..b6a5e8857db9 100644
--- a/contrib/wpa/wpa_supplicant/mesh_mpm.c
+++ b/contrib/wpa/wpa_supplicant/mesh_mpm.c
@@ -147,13 +147,13 @@ static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
/* return true if elems from a neighbor match this MBSS */
-static Boolean matches_local(struct wpa_supplicant *wpa_s,
- struct ieee802_11_elems *elems)
+static bool matches_local(struct wpa_supplicant *wpa_s,
+ struct ieee802_11_elems *elems)
{
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
if (elems->mesh_config_len < 5)
- return FALSE;
+ return false;
return (mconf->meshid_len == elems->mesh_id_len &&
os_memcmp(mconf->meshid, elems->mesh_id,
@@ -167,17 +167,17 @@ static Boolean matches_local(struct wpa_supplicant *wpa_s,
/* check if local link id is already used with another peer */
-static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+static bool llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
{
struct sta_info *sta;
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (sta->my_lid == llid)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -231,14 +231,12 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
2 + 24 + /* peering management */
- 2 + 96 + /* AMPE */
+ 2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */
2 + 16; /* MIC */
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
buf_len += 2 + 26 + /* HT capabilities */
2 + 22; /* HT operation */
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
buf_len += 2 + 12 + /* VHT Capabilities */
@@ -354,7 +352,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
wpabuf_put(buf, PMKID_LEN));
}
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
u8 ht_capa_oper[2 + 26 + 2 + 22];
@@ -362,7 +359,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
pos = hostapd_eid_ht_operation(bss, pos);
wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
@@ -537,11 +533,14 @@ static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
if (sta) {
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
MAC2STR(sta->addr));
eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
return 0;
}
@@ -696,9 +695,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
-#ifdef CONFIG_IEEE80211N
struct ieee80211_ht_operation *oper;
-#endif /* CONFIG_IEEE80211N */
int ret;
if (elems->mesh_config_len >= 7 &&
@@ -710,11 +707,12 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
}
sta = ap_get_sta(data, addr);
- if (!sta) {
- sta = ap_sta_add(data, addr);
- if (!sta)
- return NULL;
- }
+ if (sta)
+ return NULL;
+
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return NULL;
/* Set WMM by default since Mesh STAs are QoS STAs */
sta->flags |= WLAN_STA_WMM;
@@ -728,7 +726,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
-#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
oper = (struct ieee80211_ht_operation *) elems->ht_operation;
@@ -742,7 +739,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
}
update_ht_state(data, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
copy_sta_vht_capab(data, sta, elems->vht_capabilities);
@@ -876,7 +872,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
sta->addr, 0, 0, seq, sizeof(seq),
- sta->mtk, sta->mtk_len);
+ sta->mtk, sta->mtk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -885,7 +882,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
sta->addr, sta->mgtk_key_id, 0,
sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
- sta->mgtk, sta->mgtk_len);
+ sta->mgtk, sta->mgtk_len,
+ KEY_FLAG_GROUP_RX);
if (sta->igtk_len) {
wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -897,7 +895,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
wpa_cipher_to_alg(conf->mgmt_group_cipher),
sta->addr, sta->igtk_key_id, 0,
sta->igtk_rsc, sizeof(sta->igtk_rsc),
- sta->igtk, sta->igtk_len);
+ sta->igtk, sta->igtk_len,
+ KEY_FLAG_GROUP_RX);
}
}
@@ -1294,8 +1293,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) !=
- 0) {
- wpa_printf(MSG_WARNING, "MPM: %s",
+ OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "MPM: OCV failed: %s",
ocv_errorstr);
return;
}
diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.c b/contrib/wpa/wpa_supplicant/mesh_rsn.c
index 4b8d6c469173..65daa77c2c98 100644
--- a/contrib/wpa/wpa_supplicant/mesh_rsn.c
+++ b/contrib/wpa/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@ static const u8 *auth_get_psk(void *ctx, const u8 *addr,
static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct mesh_rsn *mesh_rsn = ctx;
u8 seq[6];
@@ -118,7 +119,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -165,11 +166,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
conf.wpa_group_rekey = -1;
conf.wpa_group_update_count = 4;
conf.wpa_pairwise_update_count = 4;
-#ifdef CONFIG_IEEE80211W
conf.ieee80211w = ieee80211w;
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf.ocv = ocv;
#endif /* CONFIG_OCV */
@@ -186,7 +185,6 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
return -1;
rsn->mgtk_key_id = 1;
-#ifdef CONFIG_IEEE80211W
if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
@@ -197,18 +195,20 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
rsn->igtk, rsn->igtk_len);
wpa_drv_set_key(rsn->wpa_s,
- wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher),
+ broadcast_ether_addr,
rsn->igtk_key_id, 1,
- seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
-#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
rsn->mgtk, rsn->mgtk_len);
- wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher),
+ broadcast_ether_addr,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
- rsn->mgtk, rsn->mgtk_len);
+ rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
return 0;
}
@@ -344,7 +344,6 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
}
return sae_prepare_commit(wpa_s->own_addr, sta->addr,
(u8 *) password, os_strlen(password),
- ssid->sae_password_id,
sta->sae);
}
@@ -545,10 +544,8 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
len = sizeof(*ampe);
if (cat[1] == PLINK_OPEN)
len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
-#ifdef CONFIG_IEEE80211W
if (cat[1] == PLINK_OPEN && rsn->igtk_len)
len += 2 + 6 + rsn->igtk_len;
-#endif /* CONFIG_IEEE80211W */
if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
@@ -591,7 +588,6 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
WPA_PUT_LE32(pos, 0xffffffff);
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -603,7 +599,6 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
pos += 6;
os_memcpy(pos, rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
skip_keys:
wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
@@ -774,7 +769,6 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
WPA_GET_LE32(pos));
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -794,7 +788,6 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
sta->igtk, sta->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
free:
os_free(crypt);
diff --git a/contrib/wpa/wpa_supplicant/nmake.mak b/contrib/wpa/wpa_supplicant/nmake.mak
index 80e0ac8802bc..617df036a9d2 100644
--- a/contrib/wpa/wpa_supplicant/nmake.mak
+++ b/contrib/wpa/wpa_supplicant/nmake.mak
@@ -114,7 +114,7 @@ OBJS = \
$(OBJDIR)\driver_ndis_.obj \
$(OBJDIR)\scan_helpers.obj \
$(OBJDIR)\events.obj \
- $(OBJDIR)\blacklist.obj \
+ $(OBJDIR)\bssid_ignore.obj \
$(OBJDIR)\scan.obj \
$(OBJDIR)\wpas_glue.obj \
$(OBJDIR)\eap_register.obj \
diff --git a/contrib/wpa/wpa_supplicant/notify.c b/contrib/wpa/wpa_supplicant/notify.c
index e41d7c41c61c..e0e7e5433d77 100644
--- a/contrib/wpa/wpa_supplicant/notify.c
+++ b/contrib/wpa/wpa_supplicant/notify.c
@@ -387,6 +387,11 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
wpas_notify_persistent_group_removed(wpa_s, ssid);
wpas_p2p_network_removed(wpa_s, ssid);
+
+#ifdef CONFIG_PASN
+ if (wpa_s->pasn.ssid == ssid)
+ wpa_s->pasn.ssid = NULL;
+#endif /* CONFIG_PASN */
}
@@ -794,10 +799,11 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s,
int i;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
- "depth=%d subject='%s'%s%s%s",
+ "depth=%d subject='%s'%s%s%s%s",
cert->depth, cert->subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "",
- cert->tod ? " tod=1" : "");
+ cert->tod == 2 ? " tod=2" : "",
+ cert->tod == 1 ? " tod=1" : "");
if (cert->cert) {
char *cert_hex;
diff --git a/contrib/wpa/wpa_supplicant/offchannel.c b/contrib/wpa/wpa_supplicant/offchannel.c
index b74be7dad4ac..e40cf5bbebcd 100644
--- a/contrib/wpa/wpa_supplicant/offchannel.c
+++ b/contrib/wpa/wpa_supplicant/offchannel.c
@@ -226,10 +226,10 @@ void offchannel_send_action_tx_status(
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
/* Continue the listen */
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
}
#endif /* CONFIG_P2P */
}
@@ -246,7 +246,7 @@ void offchannel_send_action_tx_status(
* @buf: Frame to transmit starting from the Category field
* @len: Length of @buf in bytes
* @wait_time: Wait time for response in milliseconds
- * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @tx_cb: Callback function for indicating TX status or %NULL for no callback
* @no_cck: Whether CCK rates are to be disallowed for TX rate selection
* Returns: 0 on success or -1 on failure
*
diff --git a/contrib/wpa/wpa_supplicant/op_classes.c b/contrib/wpa/wpa_supplicant/op_classes.c
index 6a85af4eaf37..a0ad0c2ff572 100644
--- a/contrib/wpa/wpa_supplicant/op_classes.c
+++ b/contrib/wpa/wpa_supplicant/op_classes.c
@@ -14,15 +14,22 @@
#include "utils/common.h"
#include "common/ieee802_11_common.h"
#include "wpa_supplicant_i.h"
+#include "bss.h"
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 chan,
unsigned int *flags)
{
int i;
+ bool is_6ghz = op_class >= 131 && op_class <= 136;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
+ bool chan_is_6ghz;
+
+ chan_is_6ghz = mode->channels[i].freq >= 5935 &&
+ mode->channels[i].freq <= 7115;
+ if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -40,15 +47,15 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
}
-static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel,
+ const u8 *center_channels, size_t num_chan)
{
- u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ for (i = 0; i < num_chan; i++) {
/*
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
* so the center channel is 6 channels away from the start/end.
@@ -62,13 +69,28 @@ static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
}
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
unsigned int no_ir = 0;
+ const u8 *center_channels;
+ size_t num_chan;
+ const u8 center_channels_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 };
+ const u8 center_channels_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119,
+ 135, 151, 167, 183, 199, 215 };
+
+ if (is_6ghz_op_class(op_class)) {
+ center_channels = center_channels_6ghz;
+ num_chan = ARRAY_SIZE(center_channels_6ghz);
+ } else {
+ center_channels = center_channels_5ghz;
+ num_chan = ARRAY_SIZE(center_channels_5ghz);
+ }
- center_chan = get_center_80mhz(mode, channel);
+ center_chan = get_center_80mhz(mode, channel, center_channels,
+ num_chan);
if (!center_chan)
return NOT_ALLOWED;
@@ -77,7 +99,8 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
unsigned int flags;
u8 adj_chan = center_chan - 6 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
@@ -97,15 +120,15 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
}
-static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel,
+ const u8 *center_channels, size_t num_chan)
{
- u8 center_channels[] = { 50, 114 };
unsigned int i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ for (i = 0; i < num_chan; i++) {
/*
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
* so the center channel is 14 channels away from the start/end.
@@ -120,13 +143,26 @@ static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
unsigned int no_ir = 0;
+ const u8 *center_channels;
+ size_t num_chan;
+ const u8 center_channels_5ghz[] = { 50, 114, 163 };
+ const u8 center_channels_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
+
+ if (is_6ghz_op_class(op_class)) {
+ center_channels = center_channels_6ghz;
+ num_chan = ARRAY_SIZE(center_channels_6ghz);
+ } else {
+ center_channels = center_channels_5ghz;
+ num_chan = ARRAY_SIZE(center_channels_5ghz);
+ }
- center_chan = get_center_160mhz(mode, channel);
+ center_chan = get_center_160mhz(mode, channel, center_channels,
+ num_chan);
if (!center_chan)
return NOT_ALLOWED;
@@ -135,7 +171,8 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
unsigned int flags;
u8 adj_chan = center_chan - 14 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
@@ -159,42 +196,43 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
- res2 = res = allow_channel(mode, channel, &flag);
- if (bw == BW40MINUS) {
+ res2 = res = allow_channel(mode, op_class, channel, &flag);
+ if (bw == BW40MINUS || (bw == BW40 && (((channel - 1) / 4) % 2))) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
- } else if (bw == BW40PLUS) {
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
+ } else if (bw == BW40PLUS ||
+ (bw == BW40 && !(((channel - 1) / 4) % 2))) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
} else if (bw == BW160) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 160 MHz specific version.
*/
- res2 = res = verify_160mhz(mode, channel);
+ res2 = res = verify_160mhz(mode, op_class, channel);
} else if (bw == BW80P80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -219,13 +257,14 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
int freq2 = 0;
int freq5 = 0;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
+ is_6ghz_op_class(op_class->op_class));
if (!mode)
return 0;
/* If we are configured to disable certain things, take that into
* account here. */
- if (ssid->freq_list && ssid->freq_list[0]) {
+ if (ssid && ssid->freq_list && ssid->freq_list[0]) {
for (z = 0; ; z++) {
int f = ssid->freq_list[z];
@@ -248,7 +287,7 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
return 0;
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
+ if (ssid && ssid->disable_ht) {
switch (op_class->op_class) {
case 83:
case 84:
@@ -272,7 +311,7 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
- if (ssid->disable_vht) {
+ if (ssid && ssid->disable_vht) {
if (op_class->op_class >= 128 && op_class->op_class <= 130) {
/* Disable >= 80 MHz channels if VHT is disabled */
return 0;
@@ -281,10 +320,11 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_VHT_OVERRIDES */
if (op_class->op_class == 128) {
- u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+ u8 channels[] = { 42, 58, 106, 122, 138, 155, 171 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) !=
+ if (verify_channel(mode, op_class->op_class,
+ channels[i], op_class->bw) !=
NOT_ALLOWED)
return 1;
}
@@ -294,25 +334,48 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
if (op_class->op_class == 129) {
/* Check if either 160 MHz channels is allowed */
- return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ return verify_channel(mode, op_class->op_class, 50,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 114,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 163,
+ op_class->bw) != NOT_ALLOWED;
}
if (op_class->op_class == 130) {
/* Need at least two non-contiguous 80 MHz segments */
found = 0;
- if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 42,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 58,
+ op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 171,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 171,
+ op_class->bw) != NOT_ALLOWED)
found++;
if (found >= 2)
@@ -321,10 +384,46 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
return 0;
}
+ if (op_class->op_class == 135) {
+ /* Need at least two 80 MHz segments which do not fall under the
+ * same 160 MHz segment to support 80+80 in 6 GHz.
+ */
+ int first_seg = 0;
+ int curr_seg = 0;
+
+ for (chan = op_class->min_chan; chan <= op_class->max_chan;
+ chan += op_class->inc) {
+ curr_seg++;
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
+ if (!first_seg) {
+ first_seg = curr_seg;
+ continue;
+ }
+
+ /* Supported if at least two non-consecutive 80
+ * MHz segments allowed.
+ */
+ if ((curr_seg - first_seg) > 1)
+ return 1;
+
+ /* Supported even if the 80 MHz segments are
+ * consecutive when they do not fall under the
+ * same 160 MHz segment.
+ */
+ if ((first_seg % 2) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
found = 1;
break;
}
@@ -334,9 +433,26 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
}
+static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
+ u8 *channel)
+{
+
+ const u8 *ies;
+ u8 phy_type;
+ size_t ies_len;
+
+ if (!bss)
+ return -1;
+ ies = wpa_bss_ie_ptr(bss);
+ ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current,
+ channel, &phy_type);
+}
+
+
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len)
+ struct wpa_bss *bss, u8 *pos, size_t len)
{
struct wpabuf *buf;
u8 op, current, chan;
@@ -344,11 +460,13 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
size_t res;
/*
- * Assume 20 MHz channel for now.
- * TODO: Use the secondary channel and VHT channel width that will be
- * used after association.
+ * Determine the current operating class correct mode based on
+ * advertised BSS capabilities, if available. Fall back to a less
+ * accurate guess based on frequency if the needed IEs are not available
+ * or used.
*/
- if (ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
+ if (wpas_sta_secondary_channel_offset(bss, &current, &chan) < 0 &&
+ ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
&current, &chan) == NUM_HOSTAPD_MODES)
return 0;
@@ -371,9 +489,13 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
}
*ie_len = wpabuf_len(buf) - 2;
- if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ if (*ie_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "No supported operating classes IE to add");
+ res = 0;
+ } else if (wpabuf_len(buf) > len) {
wpa_printf(MSG_ERROR,
- "Failed to add supported operating classes IE");
+ "Supported operating classes IE exceeds maximum buffer length");
res = 0;
} else {
os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
@@ -385,3 +507,24 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
wpabuf_free(buf);
return res;
}
+
+
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s)
+{
+ int op;
+ unsigned int pos, max_num = 0;
+ int *classes;
+
+ for (op = 0; global_op_class[op].op_class; op++)
+ max_num++;
+ classes = os_zalloc((max_num + 1) * sizeof(int));
+ if (!classes)
+ return NULL;
+
+ for (op = 0, pos = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, NULL, &global_op_class[op]))
+ classes[pos++] = global_op_class[op].op_class;
+ }
+
+ return classes;
+}
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.c b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
index 55b3b08efe50..62c9a26a3490 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
@@ -242,6 +242,22 @@ static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_scan_res_handled(struct wpa_supplicant *wpa_s)
+{
+ unsigned int delay = wpas_p2p_search_delay(wpa_s);
+
+ /* In case of concurrent P2P and external scans, delay P2P search. */
+ if (external_scan_running(wpa_s->radio)) {
+ delay = wpa_s->conf->p2p_search_delay;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Delay next P2P search by %d ms to let externally triggered scan complete",
+ delay);
+ }
+
+ p2p_scan_res_handled(wpa_s->global->p2p, delay);
+}
+
+
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
@@ -287,7 +303,25 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
break;
}
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
+}
+
+
+static void wpas_p2p_scan_res_fail_handler(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || !wpa_s->global->p2p)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to get scan results - try to continue");
+ wpas_p2p_scan_res_handled(wpa_s);
}
@@ -312,6 +346,15 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
"Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
}
+
+ if (!params->p2p_include_6ghz && !params->freqs) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Exclude 6 GHz channels - update the scan frequency list");
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
+ 0);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 0);
+ }
ret = wpa_drv_scan(wpa_s, params);
if (ret == 0)
wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -326,6 +369,7 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ wpa_s->scan_res_fail_handler = wpas_p2p_scan_res_fail_handler;
wpa_s->own_scan_requested = 1;
wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
@@ -350,7 +394,8 @@ static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
- const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
+ const u8 *req_dev_types, const u8 *dev_id, u16 pw_id,
+ bool include_6ghz)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_driver_scan_params *params = NULL;
@@ -388,7 +433,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
goto fail;
-
+ if (!wpa_s->conf->p2p_6ghz_disable)
+ params->p2p_include_6ghz = include_6ghz;
switch (type) {
case P2P_SCAN_SOCIAL:
params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
@@ -522,7 +568,7 @@ static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
/*
* The calling wpa_s instance is going to be removed. Do that
* from an eloop callback to keep the instance available until
- * the caller has returned. This my be needed, e.g., to provide
+ * the caller has returned. This may be needed, e.g., to provide
* control interface responses on the per-interface socket.
*/
if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
@@ -1063,9 +1109,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
"group is persistent - BSS " MACSTR
" did not include P2P IE", MAC2STR(bssid));
wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
- (u8 *) (bss + 1), bss->ie_len);
+ wpa_bss_ie_ptr(bss), bss->ie_len);
wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
- ((u8 *) bss + 1) + bss->ie_len,
+ wpa_bss_ie_ptr(bss) + bss->ie_len,
bss->beacon_ie_len);
return 0;
}
@@ -1885,6 +1931,83 @@ static void p2p_go_configured(void *ctx, void *data)
}
+/**
+ * wpas_p2p_freq_to_edmg_channel - Convert frequency into EDMG channel
+ * @freq: Frequency (MHz) to convert
+ * @op_class: Buffer for returning operating class
+ * @op_edmg_channel: Buffer for returning channel number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to find the highest channel bonding which includes the
+ * specified frequency.
+ */
+static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ u8 *op_class, u8 *op_edmg_channel)
+{
+ struct hostapd_hw_modes *hwmode;
+ struct ieee80211_edmg_config edmg;
+ unsigned int i;
+ enum chan_width chanwidth[] = {
+ CHAN_WIDTH_8640,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_4320,
+ };
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, false);
+ if (!hwmode) {
+ wpa_printf(MSG_ERROR,
+ "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
+ return -1;
+ }
+
+ /* Find the highest EDMG channel bandwidth to start the P2P GO */
+ for (i = 0; i < ARRAY_SIZE(chanwidth); i++) {
+ if (ieee80211_chaninfo_to_channel(freq, chanwidth[i], 0,
+ op_class,
+ op_edmg_channel) < 0)
+ continue;
+
+ hostapd_encode_edmg_chan(1, *op_edmg_channel, 0, &edmg);
+ if (edmg.channels &&
+ ieee802_edmg_is_allowed(hwmode->edmg, edmg)) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %u to EDMG channel %u at opclass %u",
+ freq, *op_edmg_channel, *op_class);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ u8 op_channel, op_class;
+ int freq;
+
+ /* Try social channel as primary channel frequency */
+ freq = (!params->freq) ? 58320 + 1 * 2160 : params->freq;
+
+ if (wpas_p2p_freq_to_edmg_channel(wpa_s, freq, &op_class,
+ &op_channel) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %d will be used to set an EDMG connection (channel=%u opclass=%u)",
+ freq, op_channel, op_class);
+ params->freq = freq;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int group_formation)
@@ -1921,6 +2044,20 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
ssid->he = params->he;
+ if (params->edmg) {
+ u8 op_channel, op_class;
+
+ if (!wpas_p2p_freq_to_edmg_channel(wpa_s, params->freq,
+ &op_class, &op_channel)) {
+ ssid->edmg_channel = op_channel;
+ ssid->enable_edmg = params->edmg;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Could not match EDMG channel, freq %d, for GO",
+ params->freq);
+ }
+ }
+
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1928,6 +2065,14 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
}
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ if (is_6ghz_freq(ssid->frequency) &&
+ is_p2p_6ghz_capable(wpa_s->global->p2p)) {
+ ssid->auth_alg |= WPA_AUTH_ALG_SAE;
+ ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use SAE auth_alg and key_mgmt");
+ } else {
+ p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false);
+ }
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
ssid->group_cipher = WPA_CIPHER_CCMP;
@@ -2026,6 +2171,7 @@ do { \
d->go_internet = s->go_internet;
d->go_venue_group = s->go_venue_group;
d->go_venue_type = s->go_venue_type;
+ d->p2p_add_cli_chan = s->p2p_add_cli_chan;
}
@@ -2270,6 +2416,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
res->vht = 1;
if (wpa_s->p2p_go_he)
res->he = 1;
+ if (wpa_s->p2p_go_edmg)
+ res->edmg = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
@@ -2329,7 +2477,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_start_wps_enrollee(group_wpa_s, res);
}
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2598,7 +2746,7 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- freq);
+ freq, 0);
}
@@ -3089,9 +3237,14 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0,
+ wpa_s->conf->p2p_go_ht40,
+ wpa_s->conf->p2p_go_vht,
+ 0,
+ wpa_s->conf->p2p_go_he,
+ wpa_s->conf->p2p_go_edmg, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
- 1);
+ 1, is_p2p_allow_6ghz(wpa_s->global->p2p));
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpa_msg_global(wpa_s, MSG_INFO,
@@ -3316,10 +3469,12 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
- 0, 1);
+ 0, 1,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
}
@@ -3401,19 +3556,19 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
}
-static int has_channel(struct wpa_global *global,
- struct hostapd_hw_modes *mode, u8 chan, int *flags)
+static enum chan_allowed has_channel(struct wpa_global *global,
+ struct hostapd_hw_modes *mode, u8 op_class,
+ u8 chan, int *flags)
{
int i;
unsigned int freq;
- freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
- chan * 5;
+ freq = ieee80211_chan_to_freq(NULL, op_class, chan);
if (wpas_p2p_disallowed_freq(global, freq))
return NOT_ALLOWED;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan) {
+ if ((unsigned int) mode->channels[i].freq == freq) {
if (flags)
*flags = mode->channels[i].flag;
if (mode->channels[i].flag &
@@ -3432,15 +3587,15 @@ static int has_channel(struct wpa_global *global,
static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 channel, const u8 *center_channels,
+ size_t num_chan)
{
- u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+ for (i = 0; i < num_chan; i++)
/*
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
* so the center channel is 6 channels away from the start/end.
@@ -3453,25 +3608,43 @@ static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
}
+static const u8 center_channels_5ghz_80mhz[] = { 42, 58, 106, 122, 138,
+ 155, 171 };
+static const u8 center_channels_6ghz_80mhz[] = { 7, 23, 39, 55, 71, 87, 103,
+ 119, 135, 151, 167, 183, 199,
+ 215 };
+
static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
- u8 channel, u8 bw)
+ u8 op_class, u8 channel, u8 bw)
{
u8 center_chan;
int i, flags;
enum chan_allowed res, ret = ALLOWED;
+ const u8 *chans;
+ size_t num_chans;
+ bool is_6ghz = is_6ghz_op_class(op_class);
- center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+ if (is_6ghz) {
+ chans = center_channels_6ghz_80mhz;
+ num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz);
+ } else {
+ chans = center_channels_5ghz_80mhz;
+ num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz);
+ }
+ center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel,
+ chans, num_chans);
if (!center_chan)
return NOT_ALLOWED;
- if (center_chan >= 58 && center_chan <= 138)
+ if (!is_6ghz && center_chan >= 58 && center_chan <= 138)
return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
/* check all the channels are available */
for (i = 0; i < 4; i++) {
int adj_chan = center_chan - 6 + i * 4;
- res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ res = has_channel(wpa_s->global, mode, op_class, adj_chan,
+ &flags);
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
if (res == NO_IR)
@@ -3493,15 +3666,15 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 channel, const u8 *center_channels,
+ size_t num_chan)
{
- u8 center_channels[] = { 50, 114 };
unsigned int i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+ for (i = 0; i < num_chan; i++)
/*
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
* so the center channel is 14 channels away from the start/end.
@@ -3514,15 +3687,29 @@ static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
}
+static const u8 center_channels_5ghz_160mhz[] = { 50, 114, 163 };
+static const u8 center_channels_6ghz_160mhz[] = { 15, 47, 79, 111, 143, 175,
+ 207 };
+
static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
- u8 channel, u8 bw)
+ u8 op_class, u8 channel, u8 bw)
{
u8 center_chan;
int i, flags;
enum chan_allowed res, ret = ALLOWED;
+ const u8 *chans;
+ size_t num_chans;
- center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+ if (is_6ghz_op_class(op_class)) {
+ chans = center_channels_6ghz_160mhz;
+ num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz);
+ } else {
+ chans = center_channels_5ghz_160mhz;
+ num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz);
+ }
+ center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel,
+ chans, num_chans);
if (!center_chan)
return NOT_ALLOWED;
/* VHT 160 MHz uses DFS channels in most countries. */
@@ -3531,7 +3718,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
for (i = 0; i < 8; i++) {
int adj_chan = center_chan - 14 + i * 4;
- res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ res = has_channel(wpa_s->global, mode, op_class, adj_chan,
+ &flags);
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
@@ -3560,26 +3748,46 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
}
+static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ struct ieee80211_edmg_config edmg;
+
+ hostapd_encode_edmg_chan(1, channel, 0, &edmg);
+ if (edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return ALLOWED;
+
+ return NOT_ALLOWED;
+}
+
+
static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
- u8 channel, u8 bw)
+ u8 op_class, u8 channel, u8 bw)
{
int flag = 0;
enum chan_allowed res, res2;
- res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+ res2 = res = has_channel(wpa_s->global, mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+ res2 = has_channel(wpa_s->global, mode, op_class, channel - 4,
+ NULL);
} else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+ res2 = has_channel(wpa_s->global, mode, op_class, channel + 4,
+ NULL);
} else if (bw == BW80) {
- res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ res2 = wpas_p2p_verify_80mhz(wpa_s, mode, op_class, channel,
+ bw);
} else if (bw == BW160) {
- res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
+ res2 = wpas_p2p_verify_160mhz(wpa_s, mode, op_class, channel,
+ bw);
+ } else if (bw == BW4320 || bw == BW6480 || bw == BW8640) {
+ return wpas_p2p_verify_edmg(wpa_s, mode, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3592,7 +3800,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan,
- struct p2p_channels *cli_chan)
+ struct p2p_channels *cli_chan,
+ bool p2p_disable_6ghz)
{
struct hostapd_hw_modes *mode;
int cla, op, cli_cla;
@@ -3611,36 +3820,55 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) && p2p_disable_6ghz))
continue;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+ is_6ghz_op_class(o->op_class));
if (mode == NULL)
continue;
if (mode->mode == HOSTAPD_MODE_IEEE80211G)
wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
- res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+
+ /* Check for non-continuous jump in channel index
+ * incrementation */
+ if ((o->op_class >= 128 && o->op_class <= 130) &&
+ ch < 149 && ch + o->inc > 149)
+ ch = 149;
+
+ res = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
+ ch, o->bw);
if (res == ALLOWED) {
if (reg == NULL) {
+ if (cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
o->op_class);
reg = &chan->reg_class[cla];
cla++;
reg->reg_class = o->op_class;
}
+ if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
reg->channel[reg->channels] = ch;
reg->channels++;
} else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
+ if (cli_cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
o->op_class);
cli_reg = &cli_chan->reg_class[cli_cla];
cli_cla++;
cli_reg->reg_class = o->op_class;
}
+ if (cli_reg->channels ==
+ P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
cli_reg->channel[cli_reg->channels] = ch;
cli_reg->channels++;
}
@@ -3672,7 +3900,9 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
const struct oper_class_map *o = &global_op_class[op];
u8 ch;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) &&
+ wpa_s->conf->p2p_6ghz_disable))
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -3680,7 +3910,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
(o->bw != BW40PLUS && o->bw != BW40MINUS) ||
ch != channel)
continue;
- ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
+ ch, o->bw);
if (ret == ALLOWED)
return (o->bw == BW40MINUS) ? -1 : 1;
}
@@ -3690,21 +3921,45 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel)
+ struct hostapd_hw_modes *mode, u8 channel,
+ u8 op_class)
{
- if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+ const u8 *chans;
+ size_t num_chans;
+
+ if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80))
return 0;
- return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+ if (is_6ghz_op_class(op_class)) {
+ chans = center_channels_6ghz_80mhz;
+ num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz);
+ } else {
+ chans = center_channels_5ghz_80mhz;
+ num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz);
+ }
+ return wpas_p2p_get_center_80mhz(wpa_s, mode, channel,
+ chans, num_chans);
}
int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel)
+ struct hostapd_hw_modes *mode, u8 channel,
+ u8 op_class)
{
- if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+ const u8 *chans;
+ size_t num_chans;
+
+ if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160))
return 0;
- return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+ if (is_6ghz_op_class(op_class)) {
+ chans = center_channels_6ghz_160mhz;
+ num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz);
+ } else {
+ chans = center_channels_5ghz_160mhz;
+ num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz);
+ }
+ return wpas_p2p_get_center_160mhz(wpa_s, mode, channel,
+ chans, num_chans);
}
@@ -3799,14 +4054,24 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
char ifname[100];
char force_name[100];
int ret;
+ const u8 *if_addr = NULL;
ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
wpa_s->ifname);
if (os_snprintf_error(sizeof(ifname), ret))
return -1;
+ /* Cut length at the maximum size. Note that we don't need to ensure
+ * collision free names here as the created interface is not a netdev.
+ */
+ ifname[IFNAMSIZ - 1] = '\0';
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
- ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2 &&
+ !is_zero_ether_addr(wpa_s->conf->p2p_device_persistent_mac_addr))
+ if_addr = wpa_s->conf->p2p_device_persistent_mac_addr;
+
+ ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, if_addr, NULL,
force_name, wpa_s->pending_interface_addr, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
@@ -4230,14 +4495,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
- 0, 0);
+ 0, 0, false);
} else if (response_done) {
wpas_p2p_group_add(wpa_s, 1, freq,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0, false);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4353,11 +4618,14 @@ static int wpas_prov_disc_resp_cb(void *ctx)
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
- P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
} else {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
}
return 1;
@@ -4382,6 +4650,16 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->p2p_device_random_mac_addr == 0)
return 0;
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2) {
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr) &&
+ !is_zero_ether_addr(wpa_s->own_addr)) {
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr,
+ wpa_s->own_addr, ETH_ALEN);
+ }
+ return 0;
+ }
+
if (!wpa_s->conf->ssid) {
if (random_mac_addr(addr) < 0) {
wpa_msg(wpa_s, MSG_INFO,
@@ -4483,6 +4761,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
p2p.p2ps_group_capability = p2ps_group_capability;
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
+ p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -4496,7 +4775,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.config_methods = wpa_s->wps->config_methods;
}
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels,
+ p2p.p2p_6ghz_disable)) {
wpa_printf(MSG_ERROR,
"P2P: Failed to configure supported channel list");
return -1;
@@ -4638,11 +4918,12 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->p2p_send_action_work) {
os_free(wpa_s->p2p_send_action_work->ctx);
@@ -4791,6 +5072,15 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Join operation failed - fall back to GO Negotiation");
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=join-failed");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
@@ -4942,7 +5232,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
- NULL, 0);
+ wpa_s->p2p_go_edmg,
+ NULL, 0,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
return;
}
@@ -5001,7 +5293,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from BSS table: %d MHz (SSID %s)", freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
dev_addr) == 0 &&
os_memcmp(wpa_s->pending_join_dev_addr,
wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
@@ -5140,6 +5432,14 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
if (freq > 0) {
freqs[0] = freq;
params.freqs = freqs;
+ } else if (wpa_s->conf->p2p_6ghz_disable ||
+ !is_p2p_allow_6ghz(wpa_s->global->p2p)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params,
+ 0);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params,
+ 0);
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -5170,6 +5470,8 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, &params);
+ if (params.freqs != freqs)
+ os_free(params.freqs);
if (!ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
@@ -5398,6 +5700,10 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
res = wpa_drv_get_pref_freq_list(wpa_s, iface_type,
&max_pref_freq,
pref_freq_list);
+ if (!is_p2p_allow_6ghz(wpa_s->global->p2p))
+ max_pref_freq = p2p_remove_6ghz_channels(pref_freq_list,
+ max_pref_freq);
+
if (!res && max_pref_freq > 0) {
*num_pref_freq = max_pref_freq;
i = 0;
@@ -5457,6 +5763,40 @@ exit_free:
}
+static bool is_p2p_6ghz_supported(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+ if (wpa_s->conf->p2p_6ghz_disable ||
+ !get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, true))
+ return false;
+
+ if (!p2p_wfd_enabled(wpa_s->global->p2p))
+ return false;
+ if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr))
+ return false;
+
+ return true;
+}
+
+
+static int wpas_p2p_check_6ghz(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, bool allow_6ghz, int freq)
+{
+ if (allow_6ghz && is_p2p_6ghz_supported(wpa_s, peer_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Allow connection on 6 GHz channels");
+ p2p_set_6ghz_dev_capab(wpa_s->global->p2p, true);
+ } else {
+ if (is_6ghz_freq(freq))
+ return -2;
+ p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false);
+ }
+
+ return 0;
+}
+
+
/**
* wpas_p2p_connect - Request P2P Group Formation to be started
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -5481,6 +5821,7 @@ exit_free:
* (CHANWIDTH_*).
* @group_ssid: Specific Group SSID for join or %NULL if not set
* @group_ssid_len: Length of @group_ssid in octets
+ * @allow_6ghz: Allow P2P connection on 6 GHz channels
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -5490,8 +5831,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, int he, const u8 *group_ssid,
- size_t group_ssid_len)
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len,
+ bool allow_6ghz)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5510,6 +5852,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
+ if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
+ return -2;
+
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -5522,7 +5867,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
go_intent = wpa_s->conf->p2p_go_intent;
if (!auth)
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_persistent_group = !!persistent_group;
@@ -5536,6 +5881,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
wpa_s->p2p_go_he = !!he;
+ wpa_s->p2p_go_edmg = !!edmg;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5691,19 +6037,20 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpa_s->global->p2p_long_listen,
+ offchannel_pending_action_tx(wpa_s));
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+ if (wpa_s->global->p2p_long_listen > 0)
+ wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
} else {
/*
* When listen duration is over, stop listen & update p2p_state
@@ -5734,6 +6081,8 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
+ bool calling_wpa_s_group_removed = false;
+
wpa_s = global->ifaces;
while (wpa_s) {
prev = wpa_s;
@@ -5741,9 +6090,23 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (prev->p2p_group_interface !=
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
- prev->current_ssid->p2p_group))
+ prev->current_ssid->p2p_group)) {
wpas_p2p_disconnect_safely(prev, calling_wpa_s);
+ if (prev == calling_wpa_s)
+ calling_wpa_s_group_removed = true;
+ }
}
+
+ if (!calling_wpa_s_group_removed &&
+ (calling_wpa_s->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (calling_wpa_s->current_ssid &&
+ calling_wpa_s->current_ssid->p2p_group))) {
+ wpa_printf(MSG_DEBUG, "Remove calling_wpa_s P2P group");
+ wpas_p2p_disconnect_safely(calling_wpa_s,
+ calling_wpa_s);
+ }
+
return 0;
}
@@ -5767,6 +6130,9 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO,
&size, pref_freq_list);
+ if (!is_p2p_allow_6ghz(wpa_s->global->p2p))
+ size = p2p_remove_6ghz_channels(pref_freq_list, size);
+
if (!res && size > 0) {
i = 0;
while (i < size &&
@@ -5822,10 +6188,32 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
"channel: %d MHz", freq);
} else {
+ const int freqs[] = {
+ /* operating class 115 */
+ 5180, 5200, 5220, 5240,
+ /* operating class 124 */
+ 5745, 5765, 5785, 5805,
+ };
+ unsigned int i, num_freqs = ARRAY_SIZE(freqs);
+
if (os_get_random((u8 *) &r, sizeof(r)) < 0)
return -1;
- freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+
+ /*
+ * Most of the 5 GHz channels require DFS. Only
+ * operating classes 115 and 124 are available possibly
+ * without that requirement. Check these for
+ * availability starting from a randomly picked
+ * position.
+ */
+ for (i = 0; i < num_freqs; i++, r++) {
+ freq = freqs[r % num_freqs];
+ if (p2p_supported_freq_go(wpa_s->global->p2p,
+ freq))
+ break;
+ }
+
+ if (i >= num_freqs) {
wpa_printf(MSG_DEBUG, "P2P: Could not select "
"5 GHz channel for P2P group");
return -1;
@@ -5960,6 +6348,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5975,6 +6364,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
+ params->edmg = edmg;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
@@ -6005,6 +6395,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
}
+ /* Try to use EDMG channel */
+ if (params->edmg) {
+ if (wpas_p2p_try_edmg_channel(wpa_s, params) == 0)
+ goto success;
+ params->edmg = 0;
+ }
+
/* try using the forced freq */
if (freq) {
if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
@@ -6163,14 +6560,16 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode mode;
struct hostapd_hw_modes *hwmode;
u8 chan;
+ u8 op_class;
cand = wpa_s->p2p_group_common_freqs[i];
+ op_class = is_6ghz_freq(cand) ? 133 : 128;
mode = ieee80211_freq_to_chan(cand, &chan);
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- mode);
+ mode, is_6ghz_freq(cand));
if (!hwmode ||
- wpas_p2p_verify_channel(wpa_s, hwmode, chan,
- BW80) != ALLOWED)
+ wpas_p2p_verify_channel(wpa_s, hwmode, op_class,
+ chan, BW80) != ALLOWED)
continue;
if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
params->freq = cand;
@@ -6189,20 +6588,44 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
enum hostapd_hw_mode mode;
struct hostapd_hw_modes *hwmode;
- u8 chan;
+ u8 chan, op_class;
+ bool is_6ghz, supported = false;
+ is_6ghz = is_6ghz_freq(cand);
cand = wpa_s->p2p_group_common_freqs[i];
mode = ieee80211_freq_to_chan(cand, &chan);
hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- mode);
+ mode, is_6ghz);
if (!wpas_same_band(wpa_s->current_ssid->frequency,
cand) ||
- !hwmode ||
- (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
- BW40MINUS) != ALLOWED &&
- wpas_p2p_verify_channel(wpa_s, hwmode, chan,
- BW40PLUS) != ALLOWED))
+ !hwmode)
+ continue;
+ if (is_6ghz &&
+ wpas_p2p_verify_channel(wpa_s, hwmode, 132, chan,
+ BW40) == ALLOWED)
+ supported = true;
+
+ if (!is_6ghz &&
+ ieee80211_freq_to_channel_ext(
+ cand, -1, CHANWIDTH_USE_HT, &op_class,
+ &chan) != NUM_HOSTAPD_MODES &&
+ wpas_p2p_verify_channel(
+ wpa_s, hwmode, op_class, chan,
+ BW40MINUS) == ALLOWED)
+ supported = true;
+
+ if (!supported && !is_6ghz &&
+ ieee80211_freq_to_channel_ext(
+ cand, 1, CHANWIDTH_USE_HT, &op_class,
+ &chan) != NUM_HOSTAPD_MODES &&
+ wpas_p2p_verify_channel(
+ wpa_s, hwmode, op_class, chan,
+ BW40PLUS) == ALLOWED)
+ supported = true;
+
+ if (!supported)
continue;
+
if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
params->freq = cand;
wpa_printf(MSG_DEBUG,
@@ -6322,6 +6745,8 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
* @vht_chwidth: channel bandwidth for GO operating with VHT support
+ * @edmg: Start GO with EDMG support
+ * @allow_6ghz: Allow P2P group creation on a 6 GHz channel
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
@@ -6329,12 +6754,15 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int he)
+ int max_oper_chwidth, int he, int edmg,
+ bool allow_6ghz)
{
struct p2p_go_neg_results params;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq))
+ return -1;
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -6350,7 +6778,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, NULL))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, &params);
@@ -6430,8 +6859,10 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels,
- int connection_timeout, int force_scan)
+ int connection_timeout, int force_scan,
+ bool allow_6ghz)
{
struct p2p_go_neg_results params;
int go = 0, freq;
@@ -6505,7 +6936,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, channels))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ channels))
return -1;
params.role_go = 1;
@@ -6822,10 +7254,11 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_cnt, const char **seek_string, int freq)
+ u8 seek_cnt, const char **seek_string, int freq,
+ bool include_6ghz)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning) {
@@ -6841,7 +7274,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
return p2p_find(wpa_s->global->p2p, timeout, type,
num_req_dev_types, req_dev_types, dev_id,
- search_delay, seek_cnt, seek_string, freq);
+ search_delay, seek_cnt, seek_string, freq,
+ include_6ghz);
}
@@ -6863,14 +7297,14 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
* Indicate that results have been processed so that the P2P module can
* continue pending tasks.
*/
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
}
static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
@@ -6896,7 +7330,7 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
}
@@ -6925,7 +7359,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
timeout = 3600;
}
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
/*
* Stop previous find/listen operation to avoid trying to request a new
@@ -6937,7 +7371,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
- wpa_s->p2p_long_listen = timeout * 1000;
+ wpa_s->global->p2p_long_listen = timeout * 1000;
eloop_register_timeout(timeout, 0,
wpas_p2p_long_listen_timeout,
wpa_s, NULL);
@@ -7044,7 +7478,7 @@ static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -7057,7 +7491,7 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq, int he)
+ int pref_freq, int he, int edmg, bool allow_6ghz)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7066,6 +7500,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int no_pref_freq_given = pref_freq == 0;
unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+ if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq))
+ return -1;
+
wpa_s->global->p2p_invite_group = NULL;
if (peer_addr)
os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
@@ -7078,6 +7515,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+ wpa_s->p2p_go_edmg = !!edmg;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -7139,7 +7577,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
/* Invite to join an active group */
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
- const u8 *peer_addr, const u8 *go_dev_addr)
+ const u8 *peer_addr, const u8 *go_dev_addr,
+ bool allow_6ghz)
{
struct wpa_global *global = wpa_s->global;
enum p2p_invite_role role;
@@ -7155,6 +7594,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_go_vht = 0;
wpa_s->p2p_go_vht_center_freq2 = 0;
wpa_s->p2p_go_max_oper_chwidth = 0;
+ wpa_s->p2p_go_edmg = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -7201,6 +7641,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
+ return -1;
size = P2P_MAX_PREF_CHANNELS;
res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
@@ -7776,7 +8218,8 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s,
os_memset(&chan, 0, sizeof(chan));
os_memset(&cli_chan, 0, sizeof(cli_chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan,
+ is_p2p_6ghz_disabled(wpa_s->global->p2p))) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
@@ -8100,7 +8543,9 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p));
return ret;
}
@@ -8636,9 +9081,9 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he,
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
- params->go_ssid_len);
+ params->go_ssid_len, false);
}
@@ -8716,7 +9161,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0, false);
}
@@ -8732,7 +9178,8 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0, false);
if (res)
return res;
@@ -9117,7 +9564,8 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -9217,6 +9665,8 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
{
struct p2p_go_neg_results params;
struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ void (*ap_configured_cb)(void *ctx, void *data);
+ void *ap_configured_cb_ctx, *ap_configured_cb_data;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
@@ -9226,10 +9676,18 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
/* Stop the AP functionality */
/* TODO: Should do this in a way that does not indicated to possible
* P2P Clients in the group that the group is terminated. */
+ /* If this action occurs before a group is started, the callback should
+ * be preserved, or GROUP-STARTED event would be lost. If this action
+ * occurs after a group is started, these pointers are all NULL and
+ * harmless. */
+ ap_configured_cb = wpa_s->ap_configured_cb;
+ ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;
+ ap_configured_cb_data = wpa_s->ap_configured_cb_data;
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
@@ -9248,6 +9706,11 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
return;
}
+ /* Restore preserved callback parameters */
+ wpa_s->ap_configured_cb = ap_configured_cb;
+ wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
+ wpa_s->ap_configured_cb_data = ap_configured_cb_data;
+
/* Update the frequency */
current_ssid->frequency = params.freq;
wpa_s->connect_without_scan = current_ssid;
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.h b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
index 24ec2cafc249..dee9c1bcc1e1 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
@@ -37,20 +37,22 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, int he, const u8 *group_ssid,
- size_t group_ssid_len);
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len,
+ bool allow_6ghz);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int he);
+ int max_oper_chwidth, int he, int edmg, bool allow_6ghz);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
- int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth, int he,
+ int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int he, int edmg,
const struct p2p_channels *channels,
- int connection_timeout, int force_scan);
+ int connection_timeout, int force_scan,
+ bool allow_6ghz);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
enum wpas_p2p_prov_disc_use {
@@ -73,7 +75,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_cnt, const char **seek_string, int freq);
+ u8 seek_cnt, const char **seek_string, int freq,
+ bool include_6ghz);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
@@ -116,10 +119,11 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int pref_freq, int he);
+ int vht_center_freq2, int ht40, int vht, int max_chwidth,
+ int pref_freq, int he, int edmg, bool allow_6ghz);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
- const u8 *peer_addr, const u8 *go_dev_addr);
+ const u8 *peer_addr, const u8 *go_dev_addr,
+ bool allow_6ghz);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2);
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
@@ -145,9 +149,11 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel);
+ struct hostapd_hw_modes *mode, u8 channel,
+ u8 op_class);
int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel);
+ struct hostapd_hw_modes *mode, u8 channel,
+ u8 op_class);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
const u8 *p2p_dev_addr,
@@ -165,6 +171,8 @@ int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
const struct wpabuf *sel, int forced_freq);
int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params);
#ifdef CONFIG_P2P
diff --git a/contrib/wpa/wpa_supplicant/pasn_supplicant.c b/contrib/wpa/wpa_supplicant/pasn_supplicant.c
new file mode 100644
index 000000000000..f0006ccad18d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/pasn_supplicant.c
@@ -0,0 +1,1714 @@
+/*
+ * wpa_supplicant - PASN processing
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/dragonfly.h"
+#include "common/ptksa_cache.h"
+#include "utils/eloop.h"
+#include "drivers/driver.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "eap_common/eap_defs.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "config.h"
+
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct wpa_pasn_auth_work {
+ u8 bssid[ETH_ALEN];
+ int akmp;
+ int cipher;
+ u16 group;
+ int network_id;
+ struct wpabuf *comeback;
+};
+
+
+static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork)
+{
+ wpabuf_free(awork->comeback);
+ awork->comeback = NULL;
+ os_free(awork);
+}
+
+
+static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth");
+
+ wpas_pasn_auth_stop(wpa_s);
+}
+
+
+static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "PASN: Cancel pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "pasn-start-auth", 0);
+}
+
+
+static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u8 status,
+ struct wpabuf *comeback,
+ u16 comeback_after)
+{
+ if (comeback) {
+ size_t comeback_len = wpabuf_len(comeback);
+ size_t buflen = comeback_len * 2 + 1;
+ char *comeback_txt = os_malloc(buflen);
+
+ if (comeback_txt) {
+ wpa_snprintf_hex(comeback_txt, buflen,
+ wpabuf_head(comeback), comeback_len);
+
+ wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+ " akmp=%s, status=%u comeback_after=%u comeback=%s",
+ MAC2STR(bssid),
+ wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+ status, comeback_after, comeback_txt);
+
+ os_free(comeback_txt);
+ return;
+ }
+ }
+
+ wpa_msg(wpa_s, MSG_INFO,
+ PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
+ MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+ status);
+}
+
+
+#ifdef CONFIG_SAE
+
+static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+ int ret;
+
+ ret = sae_set_group(&pasn->sae, pasn->group);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+ return NULL;
+ }
+
+ ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt,
+ wpa_s->own_addr, pasn->bssid,
+ NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+ return NULL;
+ }
+
+ /* Need to add the entire Authentication frame body */
+ buf = wpabuf_alloc(6 + SAE_COMMIT_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+
+ sae_write_commit(&pasn->sae, buf, NULL, 0);
+ pasn->sae.state = SAE_COMMITTED;
+
+ return buf;
+}
+
+
+static int wpas_pasn_wd_sae_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ const u8 *data;
+ size_t buf_len;
+ u16 len, res, alg, seq, status;
+ int groups[] = { pasn->group, 0 };
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ /* first handle the commit message */
+ if (buf_len < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (commit)");
+ return -1;
+ }
+
+ len = WPA_GET_LE16(data);
+ if (len < 6 || buf_len - 2 < len) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for commit");
+ return -1;
+ }
+
+ buf_len -= 2;
+ data += 2;
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE: commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 1 ||
+ status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit");
+ return -1;
+ }
+
+ res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups,
+ 1);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit");
+ return -1;
+ }
+
+ /* Process the commit message and derive the PMK */
+ ret = sae_process_commit(&pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+ return -1;
+ }
+
+ buf_len -= len;
+ data += len;
+
+ /* Handle the confirm message */
+ if (buf_len < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (confirm)");
+ return -1;
+ }
+
+ len = WPA_GET_LE16(data);
+ if (len < 6 || buf_len - 2 < len) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for confirm");
+ return -1;
+ }
+
+ buf_len -= 2;
+ data += 2;
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+ return -1;
+ }
+
+ res = sae_check_confirm(&pasn->sae, data + 6, len - 6);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE completed successfully");
+ pasn->sae.state = SAE_ACCEPTED;
+
+ return 0;
+}
+
+
+static struct wpabuf * wpas_pasn_wd_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+
+ /* Need to add the entire authentication frame body */
+ buf = wpabuf_alloc(6 + SAE_CONFIRM_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 2);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_confirm(&pasn->sae, buf);
+ pasn->sae.state = SAE_CONFIRMED;
+
+ return buf;
+}
+
+
+static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int group)
+{
+ const char *password = ssid->sae_password;
+ int groups[2] = { group, 0 };
+
+ if (!password)
+ password = ssid->passphrase;
+
+ if (!password) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
+ return -1;
+ }
+
+ if (ssid->pt)
+ return 0; /* PT already derived */
+
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+
+ return ssid->pt ? 0 : -1;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * wpas_pasn_fils_build_auth(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf = NULL;
+ struct wpabuf *erp_msg;
+ int ret;
+
+ erp_msg = eapol_sm_build_erp_reauth_start(wpa_s->eapol);
+ if (!erp_msg) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: ERP EAP-Initiate/Re-auth unavailable");
+ return NULL;
+ }
+
+ if (random_get_bytes(pasn->fils.nonce, FILS_NONCE_LEN) < 0 ||
+ random_get_bytes(pasn->fils.session, FILS_SESSION_LEN) < 0)
+ goto fail;
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", pasn->fils.nonce,
+ FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", pasn->fils.session,
+ FILS_SESSION_LEN);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 1);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, pasn->fils.nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, pasn->fils.session, FILS_SESSION_LEN);
+
+ /* Wrapped Data (ERP) */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, erp_msg);
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reauth message.
+ */
+ ret = fils_pmkid_erp(pasn->akmp, wpabuf_head(erp_msg),
+ wpabuf_len(erp_msg),
+ pasn->fils.erp_pmkid);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ERP PMKID");
+ goto fail;
+ }
+
+ wpabuf_free(erp_msg);
+ erp_msg = NULL;
+
+ wpa_hexdump_buf(MSG_DEBUG, "PASN: FILS: Authentication frame", buf);
+ return buf;
+fail:
+ wpabuf_free(erp_msg);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static void wpas_pasn_initiate_eapol(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct eapol_config eapol_conf;
+ struct wpa_ssid *ssid = pasn->ssid;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL");
+
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
+ eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+
+ os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.workaround = ssid->eap_workaround;
+
+ eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+}
+
+
+static struct wpabuf * wpas_pasn_wd_fils_auth(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpa_bss *bss;
+ const u8 *indic;
+ u16 fils_info;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: wrapped data - completed=%u",
+ pasn->fils.completed);
+
+ /* Nothing to add as we are done */
+ if (pasn->fils.completed)
+ return NULL;
+
+ if (!pasn->ssid) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
+ return NULL;
+ }
+
+ bss = wpa_bss_get_bssid(wpa_s, pasn->bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: BSS not found");
+ return NULL;
+ }
+
+ indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!indic || indic[1] < 2) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing FILS Indication IE");
+ return NULL;
+ }
+
+ fils_info = WPA_GET_LE16(indic + 2);
+ if (!(fils_info & BIT(9))) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS auth without PFS not supported");
+ return NULL;
+ }
+
+ wpas_pasn_initiate_eapol(wpa_s);
+
+ return wpas_pasn_fils_build_auth(wpa_s);
+}
+
+
+static int wpas_pasn_wd_fils_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ u8 rmsk[ERP_MAX_KEY_LEN];
+ size_t rmsk_len;
+ u8 anonce[FILS_NONCE_LEN];
+ const u8 *data;
+ size_t buf_len;
+ struct wpabuf *fils_wd = NULL;
+ u16 alg, seq, status;
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head(wd);
+ buf_len = wpabuf_len(wd);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Authentication frame len=%zu",
+ data, buf_len);
+
+ /* first handle the header */
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short");
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 2 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: ANonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(anonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+
+ if (os_memcmp(pasn->fils.session, elems.fils_session,
+ FILS_SESSION_LEN)) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Session mismatch");
+ return -1;
+ }
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Failed getting wrapped data");
+ return -1;
+ }
+
+ eapol_sm_process_erp_finish(wpa_s->eapol, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ wpabuf_free(fils_wd);
+ fils_wd = NULL;
+
+ if (eapol_sm_failed(wpa_s->eapol)) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: ERP finish failed");
+ return -1;
+ }
+
+ rmsk_len = ERP_MAX_KEY_LEN;
+ ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
+
+ if (ret == PMK_LEN) {
+ rmsk_len = PMK_LEN;
+ ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
+ }
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed getting RMSK");
+ return -1;
+ }
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, rmsk, rmsk_len,
+ pasn->fils.nonce, anonce, NULL, 0,
+ pasn->pmk, &pasn->pmk_len);
+
+ forced_memzero(rmsk, sizeof(rmsk));
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PMK");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: PMKID", pasn->fils.erp_pmkid,
+ PMKID_LEN);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: ERP processing succeeded");
+
+ wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
+ pasn->pmk_len, pasn->fils.erp_pmkid,
+ pasn->bssid, pasn->akmp);
+
+ pasn->fils.completed = true;
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * wpas_pasn_get_wrapped_data(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ if (pasn->using_pmksa)
+ return NULL;
+
+ switch (pasn->akmp) {
+ case WPA_KEY_MGMT_PASN:
+ /* no wrapped data */
+ return NULL;
+ case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+ if (pasn->trans_seq == 0)
+ return wpas_pasn_wd_sae_commit(wpa_s);
+ if (pasn->trans_seq == 2)
+ return wpas_pasn_wd_sae_confirm(wpa_s);
+#endif /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return wpas_pasn_wd_fils_auth(wpa_s);
+#endif /* CONFIG_FILS */
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /*
+ * Wrapped data with these AKMs is optional and is only needed
+ * for further validation of FT security parameters. For now do
+ * not use them.
+ */
+ return NULL;
+ default:
+ wpa_printf(MSG_ERROR,
+ "PASN: TODO: Wrapped data for akmp=0x%x",
+ pasn->akmp);
+ return NULL;
+ }
+}
+
+
+static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
+{
+ if (pasn->using_pmksa)
+ return WPA_PASN_WRAPPED_DATA_NO;
+
+ /* Note: Valid AKMP is expected to already be validated */
+ switch (pasn->akmp) {
+ case WPA_KEY_MGMT_SAE:
+ return WPA_PASN_WRAPPED_DATA_SAE;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ return WPA_PASN_WRAPPED_DATA_FILS_SK;
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /*
+ * Wrapped data with these AKMs is optional and is only needed
+ * for further validation of FT security parameters. For now do
+ * not use them.
+ */
+ return WPA_PASN_WRAPPED_DATA_NO;
+ case WPA_KEY_MGMT_PASN:
+ default:
+ return WPA_PASN_WRAPPED_DATA_NO;
+ }
+}
+
+
+static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *comeback)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+ const u8 *pmkid;
+ u8 wrapped_data;
+ int ret;
+ u16 capab;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 1");
+
+ if (pasn->trans_seq)
+ return NULL;
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ /* Get public key */
+ pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0);
+ pubkey = wpabuf_zeropad(pubkey, crypto_ecdh_prime_len(pasn->ecdh));
+ if (!pubkey) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+ goto fail;
+ }
+
+ wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
+
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
+
+ pmkid = NULL;
+ if (wpa_key_mgmt_ft(pasn->akmp)) {
+ ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, pasn->akmp,
+ pasn->bssid,
+ pasn->pmk_r1,
+ &pasn->pmk_r1_len,
+ pasn->pmk_r1_name);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed to derive keys");
+ goto fail;
+ }
+
+ pmkid = pasn->pmk_r1_name;
+ } else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
+ NULL, NULL, pasn->akmp);
+ if (pmksa)
+ pmkid = pmksa->pmkid;
+
+ /*
+ * Note: Even when PMKSA is available, also add wrapped data as
+ * it is possible that the PMKID is no longer valid at the AP.
+ */
+ wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
+ }
+
+ if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher) < 0)
+ goto fail;
+
+ if (!wrapped_data_buf)
+ wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
+
+ wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
+ pubkey, true, comeback, -1);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+
+ /* Add own RNSXE */
+ capab = 0;
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+ wpa_pasn_add_rsnxe(buf, capab);
+
+ ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
+ wpabuf_head_u8(buf) + IEEE80211_HDRLEN,
+ wpabuf_len(buf) - IEEE80211_HDRLEN,
+ pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ goto fail;
+ }
+
+ pasn->trans_seq++;
+
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+
+ wpa_printf(MSG_DEBUG, "PASN: Frame 1: Success");
+ return buf;
+fail:
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpabuf *buf, *wrapped_data_buf = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len, data_len;
+ const u8 *data;
+ u8 *ptr;
+ u8 wrapped_data;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 3");
+
+ if (pasn->trans_seq != 2)
+ return NULL;
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
+
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
+
+ wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
+
+ if (!wrapped_data_buf)
+ wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
+
+ wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
+ NULL, false, NULL, -1);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+ wpabuf_free(wrapped_data_buf);
+ wrapped_data_buf = NULL;
+
+ /* Add the MIC */
+ mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, mic_len);
+ ptr = wpabuf_put(buf, mic_len);
+
+ os_memset(ptr, 0, mic_len);
+
+ data = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+ data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+ ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
+ wpa_s->own_addr, pasn->bssid,
+ pasn->hash, mic_len * 2, data, data_len, mic);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed MIC calculation");
+ goto fail;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->conf->pasn_corrupt_mic) {
+ wpa_printf(MSG_DEBUG, "PASN: frame 3: Corrupt MIC");
+ mic[0] = ~mic[0];
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_memcpy(ptr, mic, mic_len);
+
+ pasn->trans_seq++;
+
+ wpa_printf(MSG_DEBUG, "PASN: frame 3: Success");
+ return buf;
+fail:
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ wpa_printf(MSG_DEBUG, "PASN: Reset");
+
+ crypto_ecdh_deinit(pasn->ecdh);
+ pasn->ecdh = NULL;
+
+ wpas_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pasn_auth_work = NULL;
+
+ eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL);
+
+ pasn->akmp = 0;
+ pasn->cipher = 0;
+ pasn->group = 0;
+ pasn->trans_seq = 0;
+ pasn->pmk_len = 0;
+ pasn->using_pmksa = false;
+
+ forced_memzero(pasn->pmk, sizeof(pasn->pmk));
+ forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
+ forced_memzero(&pasn->hash, sizeof(pasn->hash));
+
+ wpabuf_free(pasn->beacon_rsne_rsnxe);
+ pasn->beacon_rsne_rsnxe = NULL;
+
+ wpabuf_free(pasn->comeback);
+ pasn->comeback = NULL;
+ pasn->comeback_after = 0;
+
+#ifdef CONFIG_SAE
+ sae_clear_data(&pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ os_memset(&pasn->fils, 0, sizeof(pasn->fils));
+#endif /* CONFIG_FILS*/
+
+#ifdef CONFIG_IEEE80211R
+ forced_memzero(pasn->pmk_r1, sizeof(pasn->pmk_r1));
+ pasn->pmk_r1_len = 0;
+ os_memset(pasn->pmk_r1_name, 0, sizeof(pasn->pmk_r1_name));
+#endif /* CONFIG_IEEE80211R */
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+}
+
+
+static int wpas_pasn_set_pmk(struct wpa_supplicant *wpa_s,
+ struct wpa_ie_data *rsn_data,
+ struct wpa_pasn_params_data *pasn_data,
+ struct wpabuf *wrapped_data)
+{
+ static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ os_memset(pasn->pmk, 0, sizeof(pasn->pmk));
+ pasn->pmk_len = 0;
+
+ if (pasn->akmp == WPA_KEY_MGMT_PASN) {
+ wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+ pasn->pmk_len = WPA_PASN_PMK_LEN;
+ os_memcpy(pasn->pmk, pasn_default_pmk,
+ sizeof(pasn_default_pmk));
+ return 0;
+ }
+
+ if (wpa_key_mgmt_ft(pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R
+ wpa_printf(MSG_DEBUG, "PASN: FT: Using PMK-R1");
+ pasn->pmk_len = pasn->pmk_r1_len;
+ os_memcpy(pasn->pmk, pasn->pmk_r1, pasn->pmk_r1_len);
+ pasn->using_pmksa = true;
+ return 0;
+#else /* CONFIG_IEEE80211R */
+ wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+ return -1;
+#endif /* CONFIG_IEEE80211R */
+ }
+
+ if (rsn_data->num_pmkid) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
+ rsn_data->pmkid, NULL,
+ pasn->akmp);
+ if (pmksa) {
+ wpa_printf(MSG_DEBUG, "PASN: Using PMKSA");
+
+ pasn->pmk_len = pmksa->pmk_len;
+ os_memcpy(pasn->pmk, pmksa->pmk, pmksa->pmk_len);
+ pasn->using_pmksa = true;
+
+ return 0;
+ }
+ }
+
+#ifdef CONFIG_SAE
+ if (pasn->akmp == WPA_KEY_MGMT_SAE) {
+ int ret;
+
+ ret = wpas_pasn_wd_sae_rx(wpa_s, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE wrapped data");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Success deriving PMK with SAE");
+ pasn->pmk_len = PMK_LEN;
+ os_memcpy(pasn->pmk, pasn->sae.pmk, PMK_LEN);
+
+ wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
+ pasn->pmk_len, pasn->sae.pmkid,
+ pasn->bssid, pasn->akmp);
+ return 0;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ int ret;
+
+ ret = wpas_pasn_wd_fils_rx(wpa_s, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+ }
+
+ return 0;
+ }
+#endif /* CONFIG_FILS */
+
+ /* TODO: Derive PMK based on wrapped data */
+ wpa_printf(MSG_DEBUG, "PASN: Missing implementation to derive PMK");
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return -1;
+}
+
+
+static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u16 group, int freq,
+ const u8 *beacon_rsne, u8 beacon_rsne_len,
+ const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
+ int network_id, struct wpabuf *comeback)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct wpa_ssid *ssid = NULL;
+ struct wpabuf *frame;
+ int ret;
+
+ /* TODO: Currently support only ECC groups */
+ if (!dragonfly_suitable_group(group, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Reject unsuitable group %u", group);
+ return -1;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, network_id);
+
+ switch (akmp) {
+ case WPA_KEY_MGMT_PASN:
+ break;
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No network profile found for SAE");
+ return -1;
+ }
+
+ if (!ieee802_11_rsnx_capab(beacon_rsnxe,
+ WLAN_RSNX_CAPAB_SAE_H2E)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: AP does not support SAE H2E");
+ return -1;
+ }
+
+ if (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to derive PT");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_NOTHING;
+ pasn->sae.send_confirm = 0;
+ pasn->ssid = ssid;
+ break;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ pasn->ssid = ssid;
+ break;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ break;
+#endif /* CONFIG_IEEE80211R */
+ default:
+ wpa_printf(MSG_ERROR, "PASN: Unsupported AKMP=0x%x", akmp);
+ return -1;
+ }
+
+ pasn->ecdh = crypto_ecdh_init(group);
+ if (!pasn->ecdh) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+ goto fail;
+ }
+
+ pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
+ beacon_rsnxe_len);
+ if (!pasn->beacon_rsne_rsnxe) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE/RSNXE");
+ goto fail;
+ }
+
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsne, beacon_rsne_len);
+ if (beacon_rsnxe && beacon_rsnxe_len)
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsnxe,
+ beacon_rsnxe_len);
+
+ pasn->akmp = akmp;
+ pasn->cipher = cipher;
+ pasn->group = group;
+ pasn->freq = freq;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->conf->force_kdk_derivation ||
+#else
+ if (
+#endif
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF &&
+ ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ pasn->kdk_len = WPA_KDK_MAX_LEN;
+ else
+ pasn->kdk_len = 0;
+ wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+
+ os_memcpy(pasn->bssid, bssid, ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: Init: " MACSTR " akmp=0x%x, cipher=0x%x, group=%u",
+ MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
+ pasn->group);
+
+ frame = wpas_pasn_build_auth_1(wpa_s, comeback);
+ if (!frame) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
+ goto fail;
+ }
+
+ ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
+ pasn->freq, 1000);
+
+ wpabuf_free(frame);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
+ goto fail;
+ }
+
+ eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s,
+ const u8 *bssid, int akmp, int cipher)
+{
+ struct wpa_bss *bss;
+ const u8 *rsne;
+ struct wpa_ie_data rsne_data;
+ int ret;
+
+ if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not doing authentication with current BSS");
+ return NULL;
+ }
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS not found");
+ return NULL;
+ }
+
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
+ return NULL;
+ }
+
+ ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
+ return NULL;
+ }
+
+ if (!(rsne_data.key_mgmt & akmp) ||
+ !(rsne_data.pairwise_cipher & cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: AP does not support requested AKMP or cipher");
+ return NULL;
+ }
+
+ return bss;
+}
+
+
+static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_pasn_auth_work *awork = work->ctx;
+ struct wpa_bss *bss;
+ const u8 *rsne, *rsnxe;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
+
+ if (deinit) {
+ if (work->started) {
+ eloop_cancel_timeout(wpas_pasn_auth_work_timeout,
+ wpa_s, NULL);
+ wpa_s->pasn_auth_work = NULL;
+ }
+
+ wpas_pasn_free_auth_work(awork);
+ return;
+ }
+
+ /*
+ * It is possible that by the time the callback is called, the PASN
+ * authentication is not allowed, e.g., a connection with the AP was
+ * established.
+ */
+ bss = wpas_pasn_allowed(wpa_s, awork->bssid, awork->akmp,
+ awork->cipher);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed");
+ goto fail;
+ }
+
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
+ goto fail;
+ }
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+
+ ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
+ awork->group, bss->freq, rsne, *(rsne + 1) + 2,
+ rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
+ awork->network_id, awork->comeback);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+
+ /* comeback token is no longer needed at this stage */
+ wpabuf_free(awork->comeback);
+ awork->comeback = NULL;
+
+ wpa_s->pasn_auth_work = work;
+ return;
+fail:
+ wpas_pasn_free_auth_work(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ int akmp, int cipher, u16 group, int network_id,
+ const u8 *comeback, size_t comeback_len)
+{
+ struct wpa_pasn_auth_work *awork;
+ struct wpa_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR " akmp=0x%x, cipher=0x%x",
+ MAC2STR(bssid), akmp, cipher);
+
+ /*
+ * TODO: Consider modifying the offchannel logic to handle additional
+ * Management frames other then Action frames. For now allow PASN only
+ * with drivers that support off-channel TX.
+ */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Driver does not support offchannel TX");
+ return -1;
+ }
+
+ if (radio_work_pending(wpa_s, "pasn-start-auth")) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: send_auth: Work is already pending");
+ return -1;
+ }
+
+ if (wpa_s->pasn_auth_work) {
+ wpa_printf(MSG_DEBUG, "PASN: send_auth: Already in progress");
+ return -1;
+ }
+
+ bss = wpas_pasn_allowed(wpa_s, bssid, akmp, cipher);
+ if (!bss)
+ return -1;
+
+ wpas_pasn_reset(wpa_s);
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ awork->akmp = akmp;
+ awork->cipher = cipher;
+ awork->group = group;
+ awork->network_id = network_id;
+
+ if (comeback && comeback_len) {
+ awork->comeback = wpabuf_alloc_copy(comeback, comeback_len);
+ if (!awork->comeback) {
+ wpas_pasn_free_auth_work(awork);
+ return -1;
+ }
+ }
+
+ if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
+ wpas_pasn_auth_start_cb, awork) < 0) {
+ wpas_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Auth work successfully added");
+ return 0;
+}
+
+
+void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+
+ if (!wpa_s->pasn.ecdh)
+ return;
+
+ wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
+
+ wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
+ pasn->status, pasn->comeback,
+ pasn->comeback_after);
+
+ wpas_pasn_reset(wpa_s);
+}
+
+
+static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
+ struct wpas_pasn *pasn,
+ struct wpa_pasn_params_data *params)
+{
+ int akmp = pasn->akmp;
+ int cipher = pasn->cipher;
+ u16 group = pasn->group;
+ u8 bssid[ETH_ALEN];
+ int network_id = pasn->ssid ? pasn->ssid->id : 0;
+
+ wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
+ os_memcpy(bssid, pasn->bssid, ETH_ALEN);
+ wpas_pasn_reset(wpa_s);
+
+ return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group,
+ network_id,
+ params->comeback, params->comeback_len);
+}
+
+
+int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn_data;
+ struct wpa_pasn_params_data pasn_params;
+ struct wpabuf *wrapped_data = NULL, *secret = NULL, *frame = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ u16 status;
+ int ret, inc_y;
+ u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ if (!wpa_s->pasn_auth_work || !mgmt ||
+ len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ return -2;
+
+ /* Not an Authentication frame; do nothing */
+ if ((mgmt->frame_control & fc) != fc)
+ return -2;
+
+ /* Not our frame; do nothing */
+ if (os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN) != 0 ||
+ os_memcmp(mgmt->sa, pasn->bssid, ETH_ALEN) != 0 ||
+ os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN) != 0)
+ return -2;
+
+ /* Not PASN; do nothing */
+ if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
+ return -2;
+
+ if (mgmt->u.auth.auth_transaction !=
+ host_to_le16(pasn->trans_seq + 1)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: RX: Invalid transaction sequence: (%u != %u)",
+ le_to_host16(mgmt->u.auth.auth_transaction),
+ pasn->trans_seq + 1);
+ return -1;
+ }
+
+ status = le_to_host16(mgmt->u.auth.status_code);
+
+ if (status != WLAN_STATUS_SUCCESS &&
+ status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Authentication rejected - status=%u", status);
+ pasn->status = status;
+ wpas_pasn_auth_stop(wpa_s);
+ return -1;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ goto fail;
+ }
+
+ /* Check that the MIC IE exists. Save it and zero out the memory */
+ mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
+ if (status == WLAN_STATUS_SUCCESS) {
+ if (!elems.mic || elems.mic_len != mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid MIC. Expecting len=%u",
+ mic_len);
+ goto fail;
+ } else {
+ os_memcpy(mic, elems.mic, mic_len);
+ /* TODO: Clean this up.. Should not be modifying the
+ * received message buffer. */
+ os_memset((u8 *) elems.mic, 0, mic_len);
+ }
+ }
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing PASN Parameters IE");
+ goto fail;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ true, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation PASN of Parameters IE");
+ goto fail;
+ }
+
+ if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Authentication temporarily rejected");
+
+ if (pasn_params.comeback && pasn_params.comeback_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Comeback token available. After=%u",
+ pasn_params.after);
+
+ if (!pasn_params.after)
+ return wpas_pasn_immediate_retry(wpa_s, pasn,
+ &pasn_params);
+
+ pasn->comeback = wpabuf_alloc_copy(
+ pasn_params.comeback, pasn_params.comeback_len);
+ if (pasn->comeback)
+ pasn->comeback_after = pasn_params.after;
+ }
+
+ pasn->status = status;
+ goto fail;
+ }
+
+ ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+ goto fail;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+ goto fail;
+ }
+
+ if (pasn->akmp != rsn_data.key_mgmt ||
+ pasn->cipher != rsn_data.pairwise_cipher) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+ goto fail;
+ }
+
+ if (pasn->group != pasn_params.group) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in group");
+ goto fail;
+ }
+
+ if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+ goto fail;
+ }
+
+ if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+ inc_y = 1;
+ } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+ pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+ inc_y = 0;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid first octet in pubkey=0x%x",
+ pasn_params.pubkey[0]);
+ goto fail;
+ }
+
+ secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
+ pasn_params.pubkey + 1,
+ pasn_params.pubkey_len - 1);
+
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+ goto fail;
+ }
+
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ goto fail;
+ }
+ }
+
+ ret = wpas_pasn_set_pmk(wpa_s, &rsn_data, &pasn_params, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pasn->pmk, pasn->pmk_len,
+ wpa_s->own_addr, pasn->bssid,
+ wpabuf_head(secret), wpabuf_len(secret),
+ &pasn->ptk, pasn->akmp, pasn->cipher,
+ pasn->kdk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpabuf_free(wrapped_data);
+ wrapped_data = NULL;
+ wpabuf_free(secret);
+ secret = NULL;
+
+ /* Verify the MIC */
+ ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
+ pasn->bssid, wpa_s->own_addr,
+ wpabuf_head(pasn->beacon_rsne_rsnxe),
+ wpabuf_len(pasn->beacon_rsne_rsnxe),
+ (u8 *) &mgmt->u.auth,
+ len - offsetof(struct ieee80211_mgmt, u.auth),
+ out_mic);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+ if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+ goto fail;
+ }
+
+ pasn->trans_seq++;
+
+ wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
+
+ frame = wpas_pasn_build_auth_3(wpa_s);
+ if (!frame) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
+ goto fail;
+ }
+
+ ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
+ pasn->freq, 100);
+ wpabuf_free(frame);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
+
+ ptksa_cache_add(wpa_s->ptksa, pasn->bssid, pasn->cipher,
+ dot11RSNAConfigPMKLifetime, &pasn->ptk);
+
+ forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
+
+ pasn->status = WLAN_STATUS_SUCCESS;
+ return 0;
+fail:
+ wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating");
+ wpabuf_free(wrapped_data);
+ wpabuf_free(secret);
+
+ /*
+ * TODO: In case of an error the standard allows to silently drop
+ * the frame and terminate the authentication exchange. However, better
+ * reply to the AP with an error status.
+ */
+ if (status == WLAN_STATUS_SUCCESS)
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else
+ pasn->status = status;
+
+ wpas_pasn_auth_stop(wpa_s);
+ return -1;
+}
+
+
+int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t data_len, u8 acked)
+
+{
+ struct wpas_pasn *pasn = &wpa_s->pasn;
+ const struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) data;
+ u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ wpa_printf(MSG_DEBUG, "PASN: auth_tx_status: acked=%u", acked);
+
+ if (!wpa_s->pasn_auth_work) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth_tx_status: no work in progress");
+ return -1;
+ }
+
+ if (!mgmt ||
+ data_len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ return -1;
+
+ /* Not an authentication frame; do nothing */
+ if ((mgmt->frame_control & fc) != fc)
+ return -1;
+
+ /* Not our frame; do nothing */
+ if (os_memcmp(mgmt->da, pasn->bssid, ETH_ALEN) ||
+ os_memcmp(mgmt->sa, wpa_s->own_addr, ETH_ALEN) ||
+ os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN))
+ return -1;
+
+ /* Not PASN; do nothing */
+ if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
+ return -1;
+
+ if (mgmt->u.auth.auth_transaction != host_to_le16(pasn->trans_seq)) {
+ wpa_printf(MSG_ERROR,
+ "PASN: Invalid transaction sequence: (%u != %u)",
+ pasn->trans_seq,
+ le_to_host16(mgmt->u.auth.auth_transaction));
+ return 0;
+ }
+
+ wpa_printf(MSG_ERROR,
+ "PASN: auth with trans_seq=%u, acked=%u", pasn->trans_seq,
+ acked);
+
+ /*
+ * Even if the frame was not acked, do not treat this is an error, and
+ * try to complete the flow, relying on the PASN timeout callback to
+ * clean up.
+ */
+ if (pasn->trans_seq == 3) {
+ wpa_printf(MSG_DEBUG, "PASN: auth complete with: " MACSTR,
+ MAC2STR(pasn->bssid));
+ /*
+ * Either frame was not ACKed or it was ACKed but the trans_seq
+ * != 1, i.e., not expecting an RX frame, so we are done.
+ */
+ wpas_pasn_auth_stop(wpa_s);
+ }
+
+ return 0;
+}
+
+
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bss *bss;
+ struct wpabuf *buf;
+ struct ieee80211_mgmt *deauth;
+ int ret;
+
+ if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Cannot deauthenticate from current BSS");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for "
+ MACSTR, MAC2STR(bssid));
+ ptksa_cache_flush(wpa_s->ptksa, bssid, WPA_CIPHER_NONE);
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found");
+ return -1;
+ }
+
+ buf = wpabuf_alloc(64);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: deauth: Failed wpabuf allocate");
+ return -1;
+ }
+
+ deauth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.deauth.variable));
+
+ deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_DEAUTH << 4));
+
+ os_memcpy(deauth->da, bssid, ETH_ALEN);
+ os_memcpy(deauth->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(deauth->bssid, bssid, ETH_ALEN);
+ deauth->u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+ /*
+ * Since we do not expect any response from the AP, implement the
+ * Deauthentication frame transmission using direct call to the driver
+ * without a radio work.
+ */
+ ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
+ bss->freq, 0);
+
+ wpabuf_free(buf);
+ wpa_printf(MSG_DEBUG, "PASN: deauth: send_mlme ret=%d", ret);
+
+ return ret;
+}
diff --git a/contrib/wpa/wpa_supplicant/preauth_test.c b/contrib/wpa/wpa_supplicant/preauth_test.c
index 3f2da34e5bf0..97c16fb80d27 100644
--- a/contrib/wpa/wpa_supplicant/preauth_test.c
+++ b/contrib/wpa/wpa_supplicant/preauth_test.c
@@ -41,6 +41,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
const void *data, u16 data_len,
size_t *msg_len, void **data_pos)
@@ -127,7 +133,8 @@ static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -146,7 +153,9 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -184,10 +193,8 @@ static void test_eapol_clean(struct wpa_supplicant *wpa_s)
pmksa_candidate_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
scard_deinit(wpa_s->scard);
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
wpa_config_free(wpa_s->conf);
}
@@ -244,6 +251,7 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+ ctx->reconnect = _wpa_supplicant_reconnect;
wpa_s->wpa = wpa_sm_init(ctx);
assert(wpa_s->wpa != NULL);
diff --git a/contrib/wpa/wpa_supplicant/robust_av.c b/contrib/wpa/wpa_supplicant/robust_av.c
new file mode 100644
index 000000000000..39d282f0870d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/robust_av.c
@@ -0,0 +1,155 @@
+/*
+ * wpa_supplicant - Robust AV procedures
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+
+
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf)
+{
+ u8 *len, *len1;
+
+ /* MSCS descriptor element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ wpabuf_put_u8(buf, robust_av->request_type);
+ wpabuf_put_u8(buf, robust_av->up_bitmap);
+ wpabuf_put_u8(buf, robust_av->up_limit);
+ wpabuf_put_le32(buf, robust_av->stream_timeout);
+
+ if (robust_av->request_type != SCS_REQ_REMOVE) {
+ /* TCLAS mask element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len1 = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
+
+ /* Frame classifier */
+ wpabuf_put_data(buf, robust_av->frame_classifier,
+ robust_av->frame_classifier_len);
+ *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+ }
+
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+ size_t buf_len;
+ int ret;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return 0;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "AP does not support MSCS - could not send MSCS Req");
+ return -1;
+ }
+
+ if (!wpa_s->mscs_setup_done &&
+ wpa_s->robust_av.request_type != SCS_REQ_ADD) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "MSCS: Failed to send MSCS Request: request type invalid");
+ return -1;
+ }
+
+ buf_len = 3 + /* Action frame header */
+ 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+ wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
+ wpa_s->robust_av.dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
+
+ /* MSCS descriptor element */
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", buf);
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf, size_t len)
+{
+ u8 dialog_token;
+ u16 status_code;
+
+ if (len < 3)
+ return;
+
+ dialog_token = *buf++;
+ if (dialog_token != wpa_s->robust_av.dialog_token) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+ dialog_token, wpa_s->robust_av.dialog_token);
+ return;
+ }
+
+ status_code = WPA_GET_LE16(buf);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(src), status_code);
+ wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS;
+}
+
+
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *mscs_desc_ie, *mscs_status;
+ u16 status;
+
+ /* Process optional MSCS Status subelement when MSCS IE is in
+ * (Re)Association Response frame */
+ if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
+ return;
+
+ mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ if (!mscs_desc_ie || mscs_desc_ie[1] <= 8)
+ return;
+
+ /* Subelements start after (ie_id(1) + ie_len(1) + ext_id(1) +
+ * request type(1) + upc(2) + stream timeout(4) =) 10.
+ */
+ mscs_status = get_ie(&mscs_desc_ie[10], mscs_desc_ie[1] - 8,
+ MCSC_SUBELEM_STATUS);
+ if (!mscs_status || mscs_status[1] < 2)
+ return;
+
+ status = WPA_GET_LE16(mscs_status + 2);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(bssid), status);
+ wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
+}
diff --git a/contrib/wpa/wpa_supplicant/rrm.c b/contrib/wpa/wpa_supplicant/rrm.c
index 8468b2f86bd0..cf107ebaf639 100644
--- a/contrib/wpa/wpa_supplicant/rrm.c
+++ b/contrib/wpa/wpa_supplicant/rrm.c
@@ -79,7 +79,7 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
NULL);
if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
return;
}
@@ -90,8 +90,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
return;
}
wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
neighbor_rep);
wpa_s->rrm.notify_neighbor_rep = NULL;
@@ -101,10 +101,16 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
/* Workaround different, undefined for Windows, error codes used here */
+#ifndef ENOTCONN
#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
#define ECANCELED -1
#endif
+#endif
/* Measurement Request element + Location Subject + Maximum Age subelement */
#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
@@ -142,12 +148,12 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
const u8 *rrm_ie;
if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM.");
return -ENOTCONN;
}
if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection.");
return -EOPNOTSUPP;
}
@@ -155,15 +161,15 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
WLAN_EID_RRM_ENABLED_CAPABILITIES);
if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
!(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
return -EOPNOTSUPP;
}
/* Refuse if there's a live request */
if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
return -EBUSY;
}
@@ -172,14 +178,15 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
(lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
(civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
return -ENOMEM;
}
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
@@ -261,8 +268,8 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
wpabuf_free(buf);
return -ECANCELED;
}
@@ -522,7 +529,8 @@ static int * wpas_add_channels(const struct oper_class_map *op,
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
@@ -548,23 +556,32 @@ static int * wpas_add_channels(const struct oper_class_map *op,
static int * wpas_op_class_freqs(const struct oper_class_map *op,
struct hostapd_hw_modes *mode, int active)
{
- u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
- u8 channels_160mhz[] = { 50, 114 };
+ u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 };
+ u8 channels_160mhz_5ghz[] = { 50, 114, 163 };
+ u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151,
+ 167, 183, 199, 215 };
+ u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
+ const u8 *channels = NULL;
+ size_t num_chan = 0;
+ bool is_6ghz = is_6ghz_op_class(op->op_class);
/*
* When adding all channels in the operating class, 80 + 80 MHz
* operating classes are like 80 MHz channels because we add all valid
* channels anyway.
*/
- if (op->bw == BW80 || op->bw == BW80P80)
- return wpas_add_channels(op, mode, active, channels_80mhz,
- ARRAY_SIZE(channels_80mhz));
-
- if (op->bw == BW160)
- return wpas_add_channels(op, mode, active, channels_160mhz,
- ARRAY_SIZE(channels_160mhz));
+ if (op->bw == BW80 || op->bw == BW80P80) {
+ channels = is_6ghz ? channels_80mhz_6ghz : channels_80mhz_5ghz;
+ num_chan = is_6ghz ? ARRAY_SIZE(channels_80mhz_6ghz) :
+ ARRAY_SIZE(channels_80mhz_5ghz);
+ } else if (op->bw == BW160) {
+ channels = is_6ghz ? channels_160mhz_6ghz :
+ channels_160mhz_5ghz;
+ num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) :
+ ARRAY_SIZE(channels_160mhz_5ghz);
+ }
- return wpas_add_channels(op, mode, active, NULL, 0);
+ return wpas_add_channels(op, mode, active, channels, num_chan);
}
@@ -601,7 +618,8 @@ static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
pos++;
left--;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
continue;
@@ -653,7 +671,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
return NULL;
}
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
return NULL;
@@ -685,8 +704,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
}
-static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
- u8 *op_class, u8 *chan, u8 *phy_type)
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
{
const u8 *ie;
int sec_chan = 0, vht = 0;
@@ -756,10 +775,10 @@ static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
enum beacon_report_detail detail,
struct wpa_bss *bss, u8 *buf,
- size_t buf_len, u8 **ies_buf,
+ size_t buf_len, const u8 **ies_buf,
size_t *ie_len, int add_fixed)
{
- u8 *ies = *ies_buf;
+ const u8 *ies = *ies_buf;
size_t ies_len = *ie_len;
u8 *pos = buf;
int rem_len;
@@ -841,7 +860,7 @@ static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
struct wpa_bss *bss,
struct wpabuf **wpa_buf,
struct rrm_measurement_beacon_report *rep,
- u8 **ie, size_t *ie_len, u8 idx)
+ const u8 **ie, size_t *ie_len, u8 idx)
{
int ret;
u8 *buf, *pos;
@@ -908,8 +927,8 @@ static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
u64 start, u64 parent_tsf)
{
struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
- u8 *ies = (u8 *) (bss + 1);
- u8 *pos = ies;
+ const u8 *ies = wpa_bss_ie_ptr(bss);
+ const u8 *pos = ies;
size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
struct rrm_measurement_beacon_report rep;
u8 idx = 0;
diff --git a/contrib/wpa/wpa_supplicant/scan.c b/contrib/wpa/wpa_supplicant/scan.c
index 7abb028dd344..97a8d9a638d6 100644
--- a/contrib/wpa/wpa_supplicant/scan.c
+++ b/contrib/wpa/wpa_supplicant/scan.c
@@ -79,6 +79,33 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_WPS */
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+ const u8 *mac_addr)
+{
+ u8 *tmp;
+
+ if (params->mac_addr) {
+ params->mac_addr_mask = NULL;
+ os_free(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+
+ params->mac_addr_rand = 1;
+
+ if (!mac_addr)
+ return 0;
+
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+
+ os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+ params->mac_addr = tmp;
+ params->mac_addr_mask = tmp + ETH_ALEN;
+ return 0;
+}
+
+
/**
* wpa_supplicant_enabled_networks - Check whether there are enabled networks
* @wpa_s: Pointer to wpa_supplicant data
@@ -169,6 +196,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
@@ -206,6 +237,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
if (wpa_s->disconnected)
retry = 0;
+ /* do not retry if operation is not supported */
+ if (ret == -EOPNOTSUPP)
+ retry = 0;
+
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
if (wpa_s->wpa_state == WPA_SCANNING)
@@ -486,7 +521,7 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *default_ies = NULL;
u8 ext_capab[18];
- int ext_capab_len;
+ int ext_capab_len, frame_id;
enum wpa_driver_if_type type = WPA_IF_STATION;
#ifdef CONFIG_P2P
@@ -510,6 +545,20 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
wpas_mbo_scan_ie(wpa_s, default_ies);
#endif /* CONFIG_MBO */
+ if (type == WPA_IF_P2P_CLIENT)
+ frame_id = VENDOR_ELEM_PROBE_REQ_P2P;
+ else
+ frame_id = VENDOR_ELEM_PROBE_REQ;
+
+ if (wpa_s->vendor_elem[frame_id]) {
+ size_t len;
+
+ len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+ if (len > 0 && wpabuf_resize(&default_ies, len) == 0)
+ wpabuf_put_buf(default_ies,
+ wpa_s->vendor_elem[frame_id]);
+ }
+
if (default_ies)
wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
wpabuf_len(default_ies));
@@ -635,29 +684,38 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
- enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params)
+int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params, bool is_6ghz)
{
/* Include only supported channels for the specified band */
struct hostapd_hw_modes *mode;
- int count, i;
+ int num_chans = 0;
+ int *freqs, i;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
- if (mode == NULL) {
- /* No channels supported in this band - use empty list */
- params->freqs = os_zalloc(sizeof(int));
- return;
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
+ if (!mode)
+ return -1;
+
+ if (params->freqs) {
+ while (params->freqs[num_chans])
+ num_chans++;
}
- params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
- if (params->freqs == NULL)
- return;
- for (count = 0, i = 0; i < mode->num_channels; i++) {
+ freqs = os_realloc(params->freqs,
+ (num_chans + mode->num_channels + 1) * sizeof(int));
+ if (!freqs)
+ return -1;
+
+ params->freqs = freqs;
+ for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- params->freqs[count++] = mode->channels[i].freq;
+ params->freqs[num_chans++] = mode->channels[i].freq;
}
+ params->freqs[num_chans] = 0;
+
+ return 0;
}
@@ -668,12 +726,16 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
return; /* unknown what channels the driver supports */
if (params->freqs)
return; /* already using a limited channel set */
- if (wpa_s->setband == WPA_SETBAND_5G)
- wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
- params);
- else if (wpa_s->setband == WPA_SETBAND_2G)
- wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
- params);
+
+ if (wpa_s->setband_mask & WPA_SETBAND_5G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 0);
+ if (wpa_s->setband_mask & WPA_SETBAND_2G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
+ 0);
+ if (wpa_s->setband_mask & WPA_SETBAND_6G)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
+ 1);
}
@@ -1077,7 +1139,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
tssid = tssid->next) {
if (wpas_network_disabled(wpa_s, tssid))
continue;
- if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+ if (((params.freqs || !freqs_set) &&
+ tssid->scan_freq) &&
+ int_array_len(params.freqs) < 100) {
int_array_concat(&params.freqs,
tssid->scan_freq);
} else {
@@ -1163,7 +1227,12 @@ ssid_list_set:
wpa_setband_scan_freqs(wpa_s, &params);
/* See if user specified frequencies. If so, scan only those. */
- if (wpa_s->conf->freq_list && !params.freqs) {
+ if (wpa_s->last_scan_req == INITIAL_SCAN_REQ &&
+ wpa_s->conf->initial_freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->initial_freq_list");
+ int_array_concat(&params.freqs, wpa_s->conf->initial_freq_list);
+ } else if (wpa_s->conf->freq_list && !params.freqs) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Optimize scan based on conf->freq_list");
int_array_concat(&params.freqs, wpa_s->conf->freq_list);
@@ -1211,20 +1280,16 @@ ssid_list_set:
#endif /* CONFIG_P2P */
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_scan) {
- params.mac_addr = wpa_s->mac_addr_scan;
- params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
params.bssid = wpa_s->next_scan_bssid;
bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
- if (bss && bss->ssid_len && params.num_ssids == 1 &&
+ if (!wpa_s->next_scan_bssid_wildcard_ssid &&
+ bss && bss->ssid_len && params.num_ssids == 1 &&
params.ssids[0].ssid_len == 0) {
params.ssids[0].ssid = bss->ssid;
params.ssids[0].ssid_len = bss->ssid_len;
@@ -1286,6 +1351,7 @@ scan:
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
@@ -1300,6 +1366,7 @@ scan:
#ifdef CONFIG_INTERWORKING
wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
if (params.bssid)
os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
}
@@ -1664,20 +1731,16 @@ scan:
wpa_setband_scan_freqs(wpa_s, scan_params);
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_sched_scan) {
- params.mac_addr = wpa_s->mac_addr_sched_scan;
- params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
- ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params,
+ wpa_s->mac_addr_sched_scan);
wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
if (prev_state != wpa_s->wpa_state)
@@ -1837,18 +1900,15 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
+ ies = (const u8 *) (res + 1);
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, res->ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1870,22 +1930,20 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
u32 vendor_type)
{
- const u8 *end, *pos;
+ const u8 *ies;
+ const struct element *elem;
if (res->beacon_ie_len == 0)
return NULL;
- pos = (const u8 *) (res + 1);
- pos += res->ie_len;
- end = pos + res->beacon_ie_len;
+ ies = (const u8 *) (res + 1);
+ ies += res->ie_len;
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- return pos;
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
+ res->beacon_ie_len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1916,12 +1974,17 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
end = pos + res->ie_len;
while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
+ u8 ie, len;
+
+ ie = pos[0];
+ len = pos[1];
+ if (len > end - pos - 2)
break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
+ pos += 2;
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+ vendor_type == WPA_GET_BE32(pos))
+ wpabuf_put_data(buf, pos + 4, len - 4);
+ pos += len;
}
if (wpabuf_len(buf) == 0) {
@@ -1933,20 +1996,6 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
}
-/*
- * Channels with a great SNR can operate at full rate. What is a great SNR?
- * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
- * rule of thumb is that any SNR above 20 is good." This one
- * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
- * scan_est_throughput() allow even smaller SNR values for the maximum rates
- * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
- * somewhat conservative value here.
- */
-#define GREAT_SNR 25
-
-#define IS_5GHZ(n) (n > 4000)
-
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
@@ -1990,14 +2039,22 @@ static int wpa_scan_result_compar(const void *a, const void *b)
snr_b = snr_b_full = wb->level;
}
- /* if SNR is close, decide by max rate or frequency band */
- if (snr_a && snr_b && abs(snr_b - snr_a) < 7) {
+ /* If SNR is close, decide by max rate or frequency band. For cases
+ * involving the 6 GHz band, use the throughput estimate irrespective
+ * of the SNR difference since the LPI/VLP rules may result in
+ * significant differences in SNR for cases where the estimated
+ * throughput can be considerably higher with the lower SNR. */
+ if (snr_a && snr_b && (abs(snr_b - snr_a) < 7 ||
+ is_6ghz_freq(wa->freq) ||
+ is_6ghz_freq(wb->freq))) {
if (wa->est_throughput != wb->est_throughput)
return (int) wb->est_throughput -
(int) wa->est_throughput;
}
if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
+ if (is_6ghz_freq(wa->freq) ^ is_6ghz_freq(wb->freq))
+ return is_6ghz_freq(wa->freq) ? -1 : 1;
if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
return IS_5GHZ(wa->freq) ? -1 : 1;
}
@@ -2155,20 +2212,13 @@ void filter_scan_res(struct wpa_supplicant *wpa_s,
}
-/*
- * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurements. These values were
- * measured in an office environment with many APs.
- */
-#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
-#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-
void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
- res->noise = IS_5GHZ(res->freq) ?
- DEFAULT_NOISE_FLOOR_5GHZ :
- DEFAULT_NOISE_FLOOR_2GHZ;
+ res->noise = is_6ghz_freq(res->freq) ?
+ DEFAULT_NOISE_FLOOR_6GHZ :
+ (IS_5GHZ(res->freq) ?
+ DEFAULT_NOISE_FLOOR_5GHZ : DEFAULT_NOISE_FLOOR_2GHZ);
}
if (res->flags & WPA_SCAN_LEVEL_DBM) {
@@ -2181,86 +2231,220 @@ void scan_snr(struct wpa_scan_res *res)
}
-static unsigned int max_ht20_rate(int snr)
+/* Minimum SNR required to achieve a certain bitrate. */
+struct minsnr_bitrate_entry {
+ int minsnr;
+ unsigned int bitrate; /* in Mbps */
+};
+
+/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
+static const int vht_mcs = 8;
+
+static const struct minsnr_bitrate_entry vht20_table[] = {
+ { 0, 0 },
+ { 2, 6500 }, /* HT20 MCS0 */
+ { 5, 13000 }, /* HT20 MCS1 */
+ { 9, 19500 }, /* HT20 MCS2 */
+ { 11, 26000 }, /* HT20 MCS3 */
+ { 15, 39000 }, /* HT20 MCS4 */
+ { 18, 52000 }, /* HT20 MCS5 */
+ { 20, 58500 }, /* HT20 MCS6 */
+ { 25, 65000 }, /* HT20 MCS7 */
+ { 29, 78000 }, /* VHT20 MCS8 */
+ { -1, 78000 } /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry vht40_table[] = {
+ { 0, 0 },
+ { 5, 13500 }, /* HT40 MCS0 */
+ { 8, 27000 }, /* HT40 MCS1 */
+ { 12, 40500 }, /* HT40 MCS2 */
+ { 14, 54000 }, /* HT40 MCS3 */
+ { 18, 81000 }, /* HT40 MCS4 */
+ { 21, 108000 }, /* HT40 MCS5 */
+ { 23, 121500 }, /* HT40 MCS6 */
+ { 28, 135000 }, /* HT40 MCS7 */
+ { 32, 162000 }, /* VHT40 MCS8 */
+ { 34, 180000 }, /* VHT40 MCS9 */
+ { -1, 180000 } /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry vht80_table[] = {
+ { 0, 0 },
+ { 8, 29300 }, /* VHT80 MCS0 */
+ { 11, 58500 }, /* VHT80 MCS1 */
+ { 15, 87800 }, /* VHT80 MCS2 */
+ { 17, 117000 }, /* VHT80 MCS3 */
+ { 21, 175500 }, /* VHT80 MCS4 */
+ { 24, 234000 }, /* VHT80 MCS5 */
+ { 26, 263300 }, /* VHT80 MCS6 */
+ { 31, 292500 }, /* VHT80 MCS7 */
+ { 35, 351000 }, /* VHT80 MCS8 */
+ { 37, 390000 }, /* VHT80 MCS9 */
+ { -1, 390000 } /* SNR > 37 */
+};
+
+
+static const struct minsnr_bitrate_entry vht160_table[] = {
+ { 0, 0 },
+ { 11, 58500 }, /* VHT160 MCS0 */
+ { 14, 117000 }, /* VHT160 MCS1 */
+ { 18, 175500 }, /* VHT160 MCS2 */
+ { 20, 234000 }, /* VHT160 MCS3 */
+ { 24, 351000 }, /* VHT160 MCS4 */
+ { 27, 468000 }, /* VHT160 MCS5 */
+ { 29, 526500 }, /* VHT160 MCS6 */
+ { 34, 585000 }, /* VHT160 MCS7 */
+ { 38, 702000 }, /* VHT160 MCS8 */
+ { 40, 780000 }, /* VHT160 MCS9 */
+ { -1, 780000 } /* SNR > 37 */
+};
+
+
+static const struct minsnr_bitrate_entry he20_table[] = {
+ { 0, 0 },
+ { 2, 8600 }, /* HE20 MCS0 */
+ { 5, 17200 }, /* HE20 MCS1 */
+ { 9, 25800 }, /* HE20 MCS2 */
+ { 11, 34400 }, /* HE20 MCS3 */
+ { 15, 51600 }, /* HE20 MCS4 */
+ { 18, 68800 }, /* HE20 MCS5 */
+ { 20, 77400 }, /* HE20 MCS6 */
+ { 25, 86000 }, /* HE20 MCS7 */
+ { 29, 103200 }, /* HE20 MCS8 */
+ { 31, 114700 }, /* HE20 MCS9 */
+ { 34, 129000 }, /* HE20 MCS10 */
+ { 36, 143400 }, /* HE20 MCS11 */
+ { -1, 143400 } /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry he40_table[] = {
+ { 0, 0 },
+ { 5, 17200 }, /* HE40 MCS0 */
+ { 8, 34400 }, /* HE40 MCS1 */
+ { 12, 51600 }, /* HE40 MCS2 */
+ { 14, 68800 }, /* HE40 MCS3 */
+ { 18, 103200 }, /* HE40 MCS4 */
+ { 21, 137600 }, /* HE40 MCS5 */
+ { 23, 154900 }, /* HE40 MCS6 */
+ { 28, 172100 }, /* HE40 MCS7 */
+ { 32, 206500 }, /* HE40 MCS8 */
+ { 34, 229400 }, /* HE40 MCS9 */
+ { 37, 258100 }, /* HE40 MCS10 */
+ { 39, 286800 }, /* HE40 MCS11 */
+ { -1, 286800 } /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry he80_table[] = {
+ { 0, 0 },
+ { 8, 36000 }, /* HE80 MCS0 */
+ { 11, 72100 }, /* HE80 MCS1 */
+ { 15, 108100 }, /* HE80 MCS2 */
+ { 17, 144100 }, /* HE80 MCS3 */
+ { 21, 216200 }, /* HE80 MCS4 */
+ { 24, 288200 }, /* HE80 MCS5 */
+ { 26, 324300 }, /* HE80 MCS6 */
+ { 31, 360300 }, /* HE80 MCS7 */
+ { 35, 432400 }, /* HE80 MCS8 */
+ { 37, 480400 }, /* HE80 MCS9 */
+ { 40, 540400 }, /* HE80 MCS10 */
+ { 42, 600500 }, /* HE80 MCS11 */
+ { -1, 600500 } /* SNR > 37 */
+};
+
+
+static const struct minsnr_bitrate_entry he160_table[] = {
+ { 0, 0 },
+ { 11, 72100 }, /* HE160 MCS0 */
+ { 14, 144100 }, /* HE160 MCS1 */
+ { 18, 216200 }, /* HE160 MCS2 */
+ { 20, 288200 }, /* HE160 MCS3 */
+ { 24, 432400 }, /* HE160 MCS4 */
+ { 27, 576500 }, /* HE160 MCS5 */
+ { 29, 648500 }, /* HE160 MCS6 */
+ { 34, 720600 }, /* HE160 MCS7 */
+ { 38, 864700 }, /* HE160 MCS8 */
+ { 40, 960800 }, /* HE160 MCS9 */
+ { 43, 1080900 }, /* HE160 MCS10 */
+ { 45, 1201000 }, /* HE160 MCS11 */
+ { -1, 1201000 } /* SNR > 37 */
+};
+
+
+static unsigned int interpolate_rate(int snr, int snr0, int snr1,
+ int rate0, int rate1)
+{
+ return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
+}
+
+
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool vht)
+{
+ const struct minsnr_bitrate_entry *prev, *entry = table;
+
+ while ((entry->minsnr != -1) &&
+ (snr >= entry->minsnr) &&
+ (vht || entry - table <= vht_mcs))
+ entry++;
+ if (entry == table)
+ return entry->bitrate;
+ prev = entry - 1;
+ if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
+ return prev->bitrate;
+ return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
+ entry->bitrate);
+}
+
+
+static unsigned int max_ht20_rate(int snr, bool vht)
{
- if (snr < 6)
- return 6500; /* HT20 MCS0 */
- if (snr < 8)
- return 13000; /* HT20 MCS1 */
- if (snr < 13)
- return 19500; /* HT20 MCS2 */
- if (snr < 17)
- return 26000; /* HT20 MCS3 */
- if (snr < 20)
- return 39000; /* HT20 MCS4 */
- if (snr < 23)
- return 52000; /* HT20 MCS5 */
- if (snr < 24)
- return 58500; /* HT20 MCS6 */
- return 65000; /* HT20 MCS7 */
+ return max_rate(vht20_table, snr, vht);
}
-static unsigned int max_ht40_rate(int snr)
+static unsigned int max_ht40_rate(int snr, bool vht)
{
- if (snr < 3)
- return 13500; /* HT40 MCS0 */
- if (snr < 6)
- return 27000; /* HT40 MCS1 */
- if (snr < 10)
- return 40500; /* HT40 MCS2 */
- if (snr < 15)
- return 54000; /* HT40 MCS3 */
- if (snr < 17)
- return 81000; /* HT40 MCS4 */
- if (snr < 22)
- return 108000; /* HT40 MCS5 */
- if (snr < 24)
- return 121500; /* HT40 MCS6 */
- return 135000; /* HT40 MCS7 */
+ return max_rate(vht40_table, snr, vht);
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 1)
- return 0;
- if (snr < 2)
- return 29300; /* VHT80 MCS0 */
- if (snr < 5)
- return 58500; /* VHT80 MCS1 */
- if (snr < 9)
- return 87800; /* VHT80 MCS2 */
- if (snr < 11)
- return 117000; /* VHT80 MCS3 */
- if (snr < 15)
- return 175500; /* VHT80 MCS4 */
- if (snr < 16)
- return 234000; /* VHT80 MCS5 */
- if (snr < 18)
- return 263300; /* VHT80 MCS6 */
- if (snr < 20)
- return 292500; /* VHT80 MCS7 */
- if (snr < 22)
- return 351000; /* VHT80 MCS8 */
- return 390000; /* VHT80 MCS9 */
+ return max_rate(vht80_table, snr, 1);
}
-void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+static unsigned int max_vht160_rate(int snr)
{
- enum local_hw_capab capab = wpa_s->hw_capab;
- int rate; /* max legacy rate in 500 kb/s units */
- const u8 *ie;
- unsigned int est, tmp;
- int snr = res->snr;
+ return max_rate(vht160_table, snr, 1);
+}
- if (res->est_throughput)
- return;
- /* Get maximum legacy rate */
- rate = wpa_scan_get_max_rate(res);
+static unsigned int max_he_rate(const struct minsnr_bitrate_entry table[],
+ int snr)
+{
+ const struct minsnr_bitrate_entry *prev, *entry = table;
+
+ while (entry->minsnr != -1 && snr >= entry->minsnr)
+ entry++;
+ if (entry == table)
+ return 0;
+ prev = entry - 1;
+ if (entry->minsnr == -1)
+ return prev->bitrate;
+ return interpolate_rate(snr, prev->minsnr, entry->minsnr,
+ prev->bitrate, entry->bitrate);
+}
+
+
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr, int freq)
+{
+ struct hostapd_hw_modes *hw_mode;
+ unsigned int est, tmp;
+ const u8 *ie;
/* Limit based on estimated SNR */
if (rate > 1 * 2 && snr < 1)
@@ -2273,67 +2457,181 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s,
rate = 9 * 2;
else if (rate > 12 * 2 && snr < 7)
rate = 12 * 2;
+ else if (rate > 12 * 2 && snr < 8)
+ rate = 14 * 2;
+ else if (rate > 12 * 2 && snr < 9)
+ rate = 16 * 2;
else if (rate > 18 * 2 && snr < 10)
rate = 18 * 2;
else if (rate > 24 * 2 && snr < 11)
rate = 24 * 2;
+ else if (rate > 24 * 2 && snr < 12)
+ rate = 27 * 2;
+ else if (rate > 24 * 2 && snr < 13)
+ rate = 30 * 2;
+ else if (rate > 24 * 2 && snr < 14)
+ rate = 33 * 2;
else if (rate > 36 * 2 && snr < 15)
rate = 36 * 2;
+ else if (rate > 36 * 2 && snr < 16)
+ rate = 39 * 2;
+ else if (rate > 36 * 2 && snr < 17)
+ rate = 42 * 2;
+ else if (rate > 36 * 2 && snr < 18)
+ rate = 45 * 2;
else if (rate > 48 * 2 && snr < 19)
rate = 48 * 2;
+ else if (rate > 48 * 2 && snr < 20)
+ rate = 51 * 2;
else if (rate > 54 * 2 && snr < 21)
rate = 54 * 2;
est = rate * 500;
- if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+ hw_mode = get_mode_with_freq(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ freq);
+
+ if (hw_mode && hw_mode->ht_capab) {
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr);
+ tmp = max_ht20_rate(snr, false);
if (tmp > est)
est = tmp;
}
}
- if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ if (hw_mode &&
+ (hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr);
+ tmp = max_ht40_rate(snr, false);
if (tmp > est)
est = tmp;
}
}
- if (capab == CAPAB_VHT) {
+ if (hw_mode && hw_mode->vht_capab) {
/* Use +1 to assume VHT is always faster than HT */
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr) + 1;
+ bool vht80 = false, vht160 = false;
+
+ tmp = max_ht20_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr) + 1;
+ tmp = max_ht40_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
}
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
- if (ie && ie[1] >= 1 &&
- (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
+ /* Determine VHT BSS bandwidth based on IEEE Std
+ * 802.11-2020, Table 11-23 (VHT BSs bandwidth) */
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= 3) {
+ u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK;
+ u8 seg0 = ie[3];
+ u8 seg1 = ie[4];
+
+ if (cw)
+ vht80 = true;
+ if (cw == 2 ||
+ (cw == 3 &&
+ (seg1 > 0 && abs(seg1 - seg0) == 16)))
+ vht160 = true;
+ if (cw == 1 &&
+ ((seg1 > 0 && abs(seg1 - seg0) == 8) ||
+ (seg1 > 0 && abs(seg1 - seg0) == 16)))
+ vht160 = true;
+ }
+
+ if (vht80) {
tmp = max_vht80_rate(snr) + 1;
if (tmp > est)
est = tmp;
}
+
+ if (vht160 &&
+ (hw_mode->vht_capab &
+ (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ tmp = max_vht160_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+ }
}
}
- /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+ if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) {
+ /* Use +2 to assume HE is always faster than HT/VHT */
+ struct ieee80211_he_capabilities *he;
+ struct he_capabilities *own_he;
+ u8 cw;
+
+ ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES);
+ if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN))
+ return est;
+ he = (struct ieee80211_he_capabilities *) &ie[3];
+ own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA];
+
+ tmp = max_he_rate(he20_table, snr) + 2;
+ if (tmp > est)
+ est = tmp;
+
+ cw = he->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ own_he->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
+ if (cw &
+ (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G :
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
+ tmp = max_he_rate(he40_table, snr) + 2;
+ if (tmp > est)
+ est = tmp;
+ }
+
+ if (!IS_2P4GHZ(freq) &&
+ (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
+ tmp = max_he_rate(he80_table, snr) + 2;
+ if (tmp > est)
+ est = tmp;
+ }
+
+ if (!IS_2P4GHZ(freq) &&
+ (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) {
+ tmp = max_he_rate(he160_table, snr) + 2;
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+
+ return est;
+}
+
+
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ int rate; /* max legacy rate in 500 kb/s units */
+ int snr = res->snr;
+ const u8 *ies = (const void *) (res + 1);
+ size_t ie_len = res->ie_len;
+
+ if (res->est_throughput)
+ return;
+
+ /* Get maximum legacy rate */
+ rate = wpa_scan_get_max_rate(res);
+
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
+ res->est_throughput =
+ wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq);
- res->est_throughput = est;
+ /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
}
@@ -2535,23 +2833,9 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->sched_scan_plans_num = src->sched_scan_plans_num;
}
- if (src->mac_addr_rand) {
- params->mac_addr_rand = src->mac_addr_rand;
-
- if (src->mac_addr && src->mac_addr_mask) {
- u8 *mac_addr;
-
- mac_addr = os_malloc(2 * ETH_ALEN);
- if (!mac_addr)
- goto failed;
-
- os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
- os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
- ETH_ALEN);
- params->mac_addr = mac_addr;
- params->mac_addr_mask = mac_addr + ETH_ALEN;
- }
- }
+ if (src->mac_addr_rand &&
+ wpa_setup_mac_addr_rand_params(params, src->mac_addr))
+ goto failed;
if (src->bssid) {
u8 *bssid;
@@ -2566,6 +2850,7 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->relative_rssi = src->relative_rssi;
params->relative_adjust_band = src->relative_adjust_band;
params->relative_adjust_rssi = src->relative_adjust_rssi;
+ params->p2p_include_6ghz = src->p2p_include_6ghz;
return params;
failed:
@@ -2602,8 +2887,8 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, prio;
- size_t i, num_ssid, num_match_ssid;
+ int ret;
+ size_t prio, i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
struct sched_scan_plan scan_plan;
@@ -2738,18 +3023,14 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_pno) {
- params.mac_addr = wpa_s->mac_addr_pno;
- params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, &params);
ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret == 0)
wpa_s->pno = 1;
else
@@ -2843,6 +3124,32 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
}
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask)
+{
+ const u8 *to_copy;
+
+ if ((wpa_s->mac_addr_rand_enable & type) != type)
+ return -1;
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ to_copy = wpa_s->mac_addr_scan;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ to_copy = wpa_s->mac_addr_sched_scan;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ to_copy = wpa_s->mac_addr_pno;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ return -1;
+ }
+
+ os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+ return 0;
+}
+
+
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_radio_work *work;
diff --git a/contrib/wpa/wpa_supplicant/scan.h b/contrib/wpa/wpa_supplicant/scan.h
index 2aa0a8be0e4d..d1780eb09979 100644
--- a/contrib/wpa/wpa_supplicant/scan.h
+++ b/contrib/wpa/wpa_supplicant/scan.h
@@ -9,6 +9,30 @@
#ifndef SCAN_H
#define SCAN_H
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurements. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+#define DEFAULT_NOISE_FLOOR_6GHZ (-92)
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
+ */
+#define GREAT_SNR 25
+
+#define IS_2P4GHZ(n) (n >= 2412 && n <= 2484)
+#define IS_5GHZ(n) (n > 4000 && n < 5895)
+
int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
@@ -52,12 +76,21 @@ void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
void filter_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *res);
void scan_snr(struct wpa_scan_res *res);
void scan_est_throughput(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr, int freq);
void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
+int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params,
+ bool is_6ghz);
#endif /* SCAN_H */
diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c
index dd5020179f3b..f2c42ff354e7 100644
--- a/contrib/wpa/wpa_supplicant/sme.c
+++ b/contrib/wpa/wpa_supplicant/sme.c
@@ -13,6 +13,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/hw_features_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
@@ -37,9 +38,7 @@
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
@@ -86,11 +85,21 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse)
+ int reuse, int *ret_use_pt,
+ bool *ret_use_pk)
{
struct wpabuf *buf;
size_t len;
const char *password;
+ struct wpa_bss *bss;
+ int use_pt = 0;
+ bool use_pk = false;
+ u8 rsnxe_capa = 0;
+
+ if (ret_use_pt)
+ *ret_use_pt = 0;
+ if (ret_use_pk)
+ *ret_use_pk = false;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -119,6 +128,8 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
+ use_pt = wpa_s->sme.sae.h2e;
+ use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -126,18 +137,73 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL;
}
- if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ rsnxe_capa = rsnxe[2];
+ }
+
+ if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+ use_pt = 1;
+#ifdef CONFIG_SAE_PK
+ if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase)))) {
+ use_pt = 1;
+ use_pk = true;
+ }
+
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use PK with the selected AP");
+ return NULL;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
+
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 &&
+ !use_pt) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use H2E with the selected AP");
+ return NULL;
+ }
+ }
+
+ if (use_pt &&
+ sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
+ wpa_s->own_addr, bssid,
+ wpa_s->sme.sae_rejected_groups, NULL) < 0)
+ return NULL;
+ if (!use_pt &&
+ sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
- ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
- if (wpa_s->sme.sae.tmp)
+ if (wpa_s->sme.sae.tmp) {
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+ if (use_pt && use_pk)
+ wpa_s->sme.sae.pk = 1;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
+ ETH_ALEN);
+ os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+ sae_pk_set_password(&wpa_s->sme.sae, password);
+#endif /* CONFIG_SAE_PK */
+ }
reuse_data:
- len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
if (ssid->sae_password_id)
len += 4 + os_strlen(ssid->sae_password_id);
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
@@ -145,10 +211,22 @@ reuse_data:
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (use_pk)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK);
+ else if (use_pt)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ else
+ wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS);
}
- sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
- ssid->sae_password_id);
+ if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ if (ret_use_pt)
+ *ret_use_pt = use_pt;
+ if (ret_use_pk)
+ *ret_use_pk = use_pk;
return buf;
}
@@ -221,7 +299,7 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
*pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
*pos++ = rrm_ie_len;
- /* Set supported capabilites flags */
+ /* Set supported capabilities flags */
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
@@ -249,7 +327,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
const u8 *md = NULL;
#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
- int i, bssid_changed;
+ int bssid_changed;
struct wpabuf *resp = NULL;
u8 ext_capab[18];
int ext_capab_len;
@@ -259,6 +337,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif /* CONFIG_MBO */
+ int omit_rsnxe = 0;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -333,18 +412,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
- }
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#ifdef CONFIG_WEP
+ {
+ int i;
- bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
- os_memset(wpa_s->bssid, 0, ETH_ALEN);
- os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+ }
+#endif /* CONFIG_WEP */
if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
@@ -466,6 +545,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
md[0], md[1]);
+ omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX);
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -492,7 +572,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -505,7 +584,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
}
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
@@ -540,7 +618,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
sme_auth_handle_rrm(wpa_s, bss);
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
- wpa_s, ssid, bss->freq,
+ wpa_s, ssid, bss,
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
@@ -562,6 +640,27 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_s->sme.assoc_req_ie_len +=
+ wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len &&
+ !omit_rsnxe) {
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -623,7 +722,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_MBO
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
@@ -655,7 +754,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2);
+ start == 2, NULL,
+ NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -668,6 +768,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
+ bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ if (bssid_changed)
+ wpas_notify_bssid_changed(wpa_s);
+
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -761,7 +867,7 @@ no_fils:
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
wpa_clear_keys(wpa_s, bss->bssid);
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
if (old_ssid != wpa_s->current_ssid)
@@ -834,6 +940,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
struct wpa_connect_work *cwork = work->ctx;
struct wpa_supplicant *wpa_s = work->wpa_s;
+ wpa_s->roam_in_progress = false;
+
if (deinit) {
if (work->started)
wpa_s->connect_work = NULL;
@@ -855,6 +963,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -872,6 +982,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
return;
}
+ if (wpa_s->roam_in_progress) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Reject sme_authenticate() in favor of explicit roam request");
+ return;
+ }
if (radio_work_pending(wpa_s, "sme-connect")) {
/*
* The previous sme-connect work might no longer be valid due to
@@ -909,7 +1024,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
static int sme_external_auth_build_buf(struct wpabuf *buf,
struct wpabuf *params,
const u8 *sa, const u8 *da,
- u16 auth_transaction, u16 seq_num)
+ u16 auth_transaction, u16 seq_num,
+ u16 status_code)
{
struct ieee80211_mgmt *resp;
@@ -924,7 +1040,7 @@ static int sme_external_auth_build_buf(struct wpabuf *buf,
resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
resp->seq_ctrl = host_to_le16(seq_num << 4);
resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
- resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ resp->u.auth.status_code = host_to_le16(status_code);
if (params)
wpabuf_put_buf(buf, params);
@@ -937,8 +1053,12 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
struct wpabuf *resp, *buf;
+ int use_pt;
+ bool use_pk;
+ u16 status;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt,
+ &use_pk);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -952,9 +1072,15 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
}
wpa_s->sme.seq_num++;
+ if (use_pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (use_pt)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- bssid, 1, wpa_s->sme.seq_num);
- wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ bssid, 1, wpa_s->sme.seq_num, status);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -972,6 +1098,8 @@ static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
params.ssid = wpa_s->sme.ext_auth_ssid;
params.ssid_len = wpa_s->sme.ext_auth_ssid_len;
params.bssid = wpa_s->sme.ext_auth_bssid;
+ if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS)
+ params.pmkid = wpa_s->sme.sae.pmkid;
wpa_drv_send_external_auth_status(wpa_s, &params);
}
@@ -1020,8 +1148,9 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
}
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- da, 2, wpa_s->sme.seq_num);
- wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ da, 2, wpa_s->sme.seq_num,
+ WLAN_STATUS_SUCCESS);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
}
@@ -1057,6 +1186,52 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
}
+static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sme_sae_is_group_enabled(wpa_s, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
int external, const u8 *sa)
@@ -1072,11 +1247,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
int default_groups[] = { 19, 20, 21, 0 };
u16 group;
+ const u8 *token_pos;
+ size_t token_len;
+ int h2e = 0;
groups = wpa_s->conf->sae_groups;
if (!groups || groups[0] <= 0)
groups = default_groups;
+ wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
+ data, len);
if (len < sizeof(le16)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Too short SAE anti-clogging token request");
@@ -1094,8 +1274,29 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
}
wpabuf_free(wpa_s->sme.sae_token);
- wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
- len - sizeof(le16));
+ token_pos = data + sizeof(le16);
+ token_len = len - sizeof(le16);
+ h2e = wpa_s->sme.sae.h2e;
+ if (h2e) {
+ if (token_len < 3) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Too short SAE anti-clogging token container");
+ return -1;
+ }
+ if (token_pos[0] != WLAN_EID_EXTENSION ||
+ token_pos[1] == 0 ||
+ token_pos[1] > token_len - 2 ||
+ token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Invalid SAE anti-clogging token container header");
+ return -1;
+ }
+ token_len = token_pos[1] - 1;
+ token_pos += 3;
+ }
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
+ wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
+ wpa_s->sme.sae_token);
if (!external)
sme_send_authentication(wpa_s, wpa_s->current_bss,
wpa_s->current_ssid, 2);
@@ -1111,6 +1312,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpa_s->sme.sae.state == SAE_COMMITTED &&
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
@@ -1135,8 +1338,17 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
+ status_code != WLAN_STATUS_SAE_PK) {
+ const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR
+ " auth_type=%u auth_transaction=%u status_code=%u",
+ MAC2STR(bssid), WLAN_AUTH_SAE,
+ auth_transaction, status_code);
return -1;
+ }
if (auth_transaction == 1) {
u16 res;
@@ -1147,12 +1359,35 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ if (wpa_s->sme.sae.state != SAE_COMMITTED) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Ignore commit message while waiting for confirm");
+ return 0;
+ }
+ if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
+ return -1;
+ }
+ if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
+ return -1;
+ }
+ if (!wpa_s->sme.sae.pk &&
+ status_code == WLAN_STATUS_SAE_PK) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
return -1;
+ }
+
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
- groups);
+ groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1161,6 +1396,12 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if (res != WLAN_STATUS_SUCCESS)
return -1;
+ if (wpa_s->sme.sae.tmp &&
+ sme_check_sae_rejected_groups(
+ wpa_s,
+ wpa_s->sme.sae.tmp->peer_rejected_groups))
+ return -1;
+
if (sae_process_commit(&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
@@ -1176,6 +1417,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
@@ -1197,6 +1440,37 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
}
+static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ wpa_printf(MSG_DEBUG,
+ "SME: SAE completed - setting PMK for 4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->sme.sae.pmkid, bssid);
+ if (wpa_s->conf->sae_pmkid_in_assoc) {
+ /* Update the own RSNE contents now that we have set the PMK
+ * and added a PMKSA cache entry based on the successfully
+ * completed SAE exchange. In practice, this will add the PMKID
+ * into RSNE. */
+ if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Not enough room for inserting own PMKID into RSNE");
+ return -1;
+ }
+ if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ wpa_s->sme.sae.pmkid) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Updated Association Request IEs",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ }
+
+ return 0;
+}
+
+
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
const u8 *auth_frame, size_t len)
{
@@ -1230,10 +1504,8 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
if (res != 1)
return;
- wpa_printf(MSG_DEBUG,
- "SME: SAE completed - setting PMK for 4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
+ return;
}
}
@@ -1277,7 +1549,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
int res;
res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
data->auth.status_code, data->auth.ies,
- data->auth.ies_len, 0, NULL);
+ data->auth.ies_len, 0, data->auth.peer);
if (res < 0) {
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@@ -1286,10 +1558,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
if (res != 1)
return;
- wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
- "4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0)
+ return;
}
#endif /* CONFIG_SAE */
@@ -1442,6 +1712,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
{
struct wpa_driver_associate_params params;
struct ieee802_11_elems elems;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
#ifdef CONFIG_FILS
u8 nonces[2 * FILS_NONCE_LEN];
#endif /* CONFIG_FILS */
@@ -1551,8 +1822,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
struct wpabuf *owe_ie;
u16 group;
- if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
- group = wpa_s->current_ssid->owe_group;
+ if (ssid && ssid->owe_group) {
+ group = ssid->owe_group;
} else if (wpa_s->assoc_status_code ==
WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
if (wpa_s->last_owe_group == 19)
@@ -1588,9 +1859,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
- wpa_s->current_ssid->dpp_netaccesskey) {
- struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && ssid &&
+ ssid->dpp_netaccesskey && ssid->dpp_pfs != 2 &&
+ !ssid->dpp_pfs_fallback) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (!pmksa || !pmksa->dpp_pfs)
+ goto pfs_fail;
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
@@ -1617,7 +1893,41 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
pfs_fail:
#endif /* CONFIG_DPP2 */
- if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+ wpa_s->mscs_setup_done = false;
+ if (wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS) &&
+ wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
+ max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
+ wpabuf_head(mscs_ie), mscs_ie_len);
+ *wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
+ if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
multi_ap_ie_len = add_multi_ap_ie(
@@ -1637,8 +1947,7 @@ pfs_fail:
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq.freq = wpa_s->sme.freq;
- params.bg_scan_period = wpa_s->current_ssid ?
- wpa_s->current_ssid->bg_scan_period : -1;
+ params.bg_scan_period = ssid ? ssid->bg_scan_period : -1;
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
@@ -1654,15 +1963,18 @@ pfs_fail:
os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
params.htcaps = (u8 *) &htcaps;
params.htcaps_mask = (u8 *) &htcaps_mask;
- wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+ wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
os_memset(&vhtcaps, 0, sizeof(vhtcaps));
os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
params.vhtcaps = &vhtcaps;
params.vhtcaps_mask = &vhtcaps_mask;
- wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+ wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
@@ -1778,7 +2090,12 @@ pfs_fail:
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
- if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ if (ssid && ssid->p2p_group)
params.p2p = 1;
if (wpa_s->p2pdev->set_sta_uapsd)
@@ -1995,15 +2312,17 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
}
void sme_deinit(struct wpa_supplicant *wpa_s)
{
sme_clear_on_disassoc(wpa_s);
+#ifdef CONFIG_SAE
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -2061,13 +2380,14 @@ static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
}
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
const u8 *ie;
- u16 ht_cap;
u8 chan_list[P2P_MAX_CHANNELS], channel;
u8 num_channels = 0, num_intol = 0, i;
+ size_t j;
+ int pri_freq, sec_freq;
if (!wpa_s->sme.sched_obss_scan)
return 0;
@@ -2095,22 +2415,36 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
os_memset(chan_list, 0, sizeof(chan_list));
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- /* Skip other band bss */
+ pri_freq = wpa_s->assoc_freq;
+
+ switch (wpa_s->sme.ht_sec_chan) {
+ case HT_SEC_CHAN_ABOVE:
+ sec_freq = pri_freq + 20;
+ break;
+ case HT_SEC_CHAN_BELOW:
+ sec_freq = pri_freq - 20;
+ break;
+ case HT_SEC_CHAN_UNKNOWN:
+ default:
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Undefined secondary channel: drop OBSS scan results");
+ return 1;
+ }
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *bss = scan_res->res[j];
enum hostapd_hw_mode mode;
+ int res;
+
+ /* Skip other band bss */
mode = ieee80211_freq_to_chan(bss->freq, &channel);
if (mode != HOSTAPD_MODE_IEEE80211G &&
mode != HOSTAPD_MODE_IEEE80211B)
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
- ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
- wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
- " freq=%u chan=%u ht_cap=0x%x",
- MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
-
- if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
- if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ res = check_bss_coex_40mhz(bss, pri_freq, sec_freq);
+ if (res) {
+ if (res == 2)
num_intol++;
/* Check whether the channel is already considered */
@@ -2139,7 +2473,7 @@ static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
int start, end;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211G);
+ HOSTAPD_MODE_IEEE80211G, false);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -2292,8 +2626,6 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
}
-#ifdef CONFIG_IEEE80211W
-
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
@@ -2341,6 +2673,16 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Request OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_req);
+ ci.frequency = wpa_s->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
return;
@@ -2434,6 +2776,10 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
return;
if (wpa_s->sme.sa_query_count > 0)
return;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_sa_query)
+ return;
+#endif /* CONFIG_TESTING_OPTIONS */
os_get_reltime(&now);
if (wpa_s->sme.last_unprot_disconnect.sec &&
@@ -2491,6 +2837,16 @@ static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Response OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_resp);
+ ci.frequency = wpa_s->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
return;
@@ -2540,11 +2896,17 @@ static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s,
}
-void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa,
const u8 *data, size_t len)
{
if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN)
return;
+ if (is_multicast_ether_addr(da)) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11: Ignore group-addressed SA Query frame (A1=" MACSTR " A2=" MACSTR ")",
+ MAC2STR(da), MAC2STR(sa));
+ return;
+ }
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from "
MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
@@ -2570,8 +2932,11 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR
+ " frame=saquery%s error=%s",
+ MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
@@ -2582,5 +2947,3 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
else if (data[0] == WLAN_SA_QUERY_RESPONSE)
sme_process_sa_query_response(wpa_s, sa, data, len);
}
-
-#endif /* CONFIG_IEEE80211W */
diff --git a/contrib/wpa/wpa_supplicant/sme.h b/contrib/wpa/wpa_supplicant/sme.h
index 1a7f9e8320c7..ecbc16dacd9d 100644
--- a/contrib/wpa/wpa_supplicant/sme.h
+++ b/contrib/wpa/wpa_supplicant/sme.h
@@ -29,7 +29,7 @@ void sme_event_disassoc(struct wpa_supplicant *wpa_s,
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code);
void sme_event_ch_switch(struct wpa_supplicant *wpa_s);
-void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa,
const u8 *data, size_t len);
void sme_state_changed(struct wpa_supplicant *wpa_s);
void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
@@ -37,7 +37,8 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
void sme_deinit(struct wpa_supplicant *wpa_s);
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
union wpa_event_data *data);
@@ -112,7 +113,8 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
-static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
return 0;
}
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 03ac50705995..da69a8705ce8 100644
--- a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
+WantedBy=multi-user.target
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index c8a744d6e138..ca3054bc6d55 100644
--- a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
+WantedBy=multi-user.target
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index 7788b380c4a2..55d2b9c81712 100644
--- a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -12,4 +12,4 @@ Type=simple
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant@%i.service
+WantedBy=multi-user.target
diff --git a/contrib/wpa/wpa_supplicant/twt.c b/contrib/wpa/wpa_supplicant/twt.c
new file mode 100644
index 000000000000..8ec2c85acb8d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/twt.c
@@ -0,0 +1,142 @@
+/*
+ * wpa_supplicant - TWT
+ * Copyright (c) 2003-2016, 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 "utils/common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+/**
+ * wpas_twt_send_setup - Send TWT Setup frame (Request) to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @dtok: Dialog token
+ * @exponent: Wake-interval exponent
+ * @mantissa: Wake-interval mantissa
+ * @min_twt: Minimum TWT wake duration in units of 256 usec
+ * @setup_cmd: 0 == request, 1 == suggest, etc. Table 9-297
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
+ int mantissa, u8 min_twt, int setup_cmd, u64 twt,
+ bool requestor, bool trigger, bool implicit,
+ bool flow_type, u8 flow_id, bool protection,
+ u8 twt_channel, u8 control)
+{
+ struct wpabuf *buf;
+ u16 req_type = 0;
+ int ret = 0;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "TWT: No connection - cannot send TWT Setup frame");
+ return -ENOTCONN;
+ }
+
+ /* 3 = Action category + Action code + Dialog token */
+ /* 17 = TWT element */
+ buf = wpabuf_alloc(3 + 17);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "TWT: Failed to allocate TWT Setup frame (Request)");
+ return -ENOMEM;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TWT: Setup request, dtok: %d exponent: %d mantissa: %d min-twt: %d",
+ dtok, exponent, mantissa, min_twt);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_S1G);
+ wpabuf_put_u8(buf, S1G_ACT_TWT_SETUP);
+ wpabuf_put_u8(buf, dtok);
+
+ wpabuf_put_u8(buf, WLAN_EID_TWT);
+ wpabuf_put_u8(buf, 15); /* len */
+
+ wpabuf_put_u8(buf, control);
+
+ if (requestor)
+ req_type |= BIT(0); /* This STA is a TWT Requesting STA */
+ /* TWT Setup Command field */
+ req_type |= (setup_cmd & 0x7) << 1;
+ if (trigger)
+ req_type |= BIT(4); /* TWT SP includes trigger frames */
+ if (implicit)
+ req_type |= BIT(5); /* Implicit TWT */
+ if (flow_type)
+ req_type |= BIT(6); /* Flow Type: Unannounced TWT */
+ req_type |= (flow_id & 0x7) << 7;
+ req_type |= (exponent & 0x1f) << 10; /* TWT Wake Interval Exponent */
+ if (protection)
+ req_type |= BIT(15);
+ wpabuf_put_le16(buf, req_type);
+ wpabuf_put_le64(buf, twt);
+ wpabuf_put_u8(buf, min_twt); /* Nominal Minimum TWT Wake Duration */
+ wpabuf_put_le16(buf, mantissa); /* TWT Wake Interval Mantissa */
+ wpabuf_put_u8(buf, twt_channel); /* TWT Channel */
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_printf(MSG_DEBUG, "TWT: Failed to send TWT Setup Request");
+ ret = -ECANCELED;
+ }
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+/**
+ * wpas_twt_send_teardown - Send TWT teardown request to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @flags: The byte that goes inside the TWT Teardown element
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "TWT: No connection - cannot send TWT Teardown frame");
+ return -ENOTCONN;
+ }
+
+ /* 3 = Action category + Action code + flags */
+ buf = wpabuf_alloc(3);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "TWT: Failed to allocate TWT Teardown frame");
+ return -ENOMEM;
+ }
+
+ wpa_printf(MSG_DEBUG, "TWT: Teardown request, flags: 0x%x", flags);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_S1G);
+ wpabuf_put_u8(buf, S1G_ACT_TWT_TEARDOWN);
+ wpabuf_put_u8(buf, flags);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_printf(MSG_DEBUG, "TWT: Failed to send TWT Teardown frame");
+ ret = -ECANCELED;
+ }
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
index af7b3fe9ceb0..c92b8fd89d6c 100755
--- a/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
+++ b/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
@@ -215,7 +215,7 @@
>
</File>
<File
- RelativePath="..\..\blacklist.c"
+ RelativePath="..\..\bssid_ignore.c"
>
</File>
<File
@@ -231,6 +231,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\utils\config.c"
+ >
+ </File>
+ <File
RelativePath="..\..\config.c"
>
</File>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
index 51acab9270c6..10c05b565597 100755
--- a/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
@@ -215,7 +215,7 @@
>
</File>
<File
- RelativePath="..\..\blacklist.c"
+ RelativePath="..\..\bssid_ignore.c"
>
</File>
<File
@@ -231,6 +231,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\utils\config.c"
+ >
+ </File>
+ <File
RelativePath="..\..\config.c"
>
</File>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
index 6fd8af80303b..82d9033ffe8e 100755
--- a/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
@@ -215,7 +215,7 @@
>
</File>
<File
- RelativePath="..\..\blacklist.c"
+ RelativePath="..\..\bssid_ignore.c"
>
</File>
<File
@@ -231,6 +231,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\utils\config.c"
+ >
+ </File>
+ <File
RelativePath="..\..\config.c"
>
</File>
diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.c b/contrib/wpa/wpa_supplicant/wmm_ac.c
index 38800cc77fb7..d0fdd55d30fc 100644
--- a/contrib/wpa/wpa_supplicant/wmm_ac.c
+++ b/contrib/wpa/wpa_supplicant/wmm_ac.c
@@ -400,7 +400,7 @@ static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
req_ac = up_to_ac[params->user_priority];
- /* Requested accesss category must have acm */
+ /* Requested access category must have acm */
if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
return 0;
diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.c b/contrib/wpa/wpa_supplicant/wnm_sta.c
index c14764963b78..8a1a44690ba5 100644
--- a/contrib/wpa/wpa_supplicant/wnm_sta.c
+++ b/contrib/wpa/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_wnm_sleep);
+ ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -271,7 +280,6 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
WNM_SLEEP_SUBELEM_GTK,
ptr);
ptr += 13 + gtk_len;
-#ifdef CONFIG_IEEE80211W
} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
@@ -281,7 +289,15 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
-#endif /* CONFIG_IEEE80211W */
+ } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
+ if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BIGTK subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_BIGTK, ptr);
+ ptr += 10 + WPA_BIGTK_LEN;
} else
break; /* skip the loop */
}
@@ -367,8 +383,9 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
@@ -535,7 +552,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
freq = 2407 + chan * 5;
else if (chan == 14)
freq = 2484;
- else if (chan >= 36 && chan <= 169)
+ else if (chan >= 36 && chan <= 177)
freq = 5000 + chan * 5;
}
return freq;
@@ -1326,11 +1343,11 @@ static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
continue;
bss = wpa_s->current_bss;
ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
- if (bss && ssid_ie &&
+ if (bss && ssid_ie && ssid_ie[1] &&
(bss->ssid_len != ssid_ie[1] ||
os_memcmp(bss->ssid, ssid_ie + 2,
bss->ssid_len) != 0))
- continue;
+ continue; /* Skip entries for other ESSs */
/* Potential candidate found */
found = 1;
@@ -1371,7 +1388,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *vendor;
#endif /* CONFIG_MBO */
- if (wpa_s->conf->disable_btm)
+ if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
return;
if (end - pos < 5)
diff --git a/contrib/wpa/wpa_supplicant/wpa_cli.c b/contrib/wpa/wpa_supplicant/wpa_cli.c
index 9ad2e3ef2144..215ac4975cb5 100644
--- a/contrib/wpa/wpa_supplicant/wpa_cli.c
+++ b/contrib/wpa/wpa_supplicant/wpa_cli.c
@@ -52,6 +52,7 @@ static char *ctrl_ifname = NULL;
static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
+static int reconnect = 0;
static int ping_interval = 5;
static int interactive = 0;
static char *ifname_prefix = NULL;
@@ -80,7 +81,7 @@ static void update_ifnames(struct wpa_ctrl *ctrl);
static void usage(void)
{
- printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+ printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvBr] "
"[-a<action file>] \\\n"
" [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
"\\\n"
@@ -91,6 +92,8 @@ static void usage(void)
" -a = run in daemon mode executing the action file based on "
"events from\n"
" wpa_supplicant\n"
+ " -r = try to reconnect when client socket is disconnected.\n"
+ " This is useful only when used with -a.\n"
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
@@ -474,7 +477,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
- "ip_addr_start", "ip_addr_end",
+ "ip_addr_start", "ip_addr_end", "p2p_go_edmg",
#endif /* CONFIG_P2P */
"country", "bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
@@ -490,7 +493,8 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"sae_groups", "dtim_period", "beacon_int",
"ap_vendor_elements", "ignore_old_scan_res", "freq_list",
- "scan_cur_freq", "sched_scan_interval",
+ "scan_cur_freq", "scan_res_valid_for_connect",
+ "sched_scan_interval",
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
@@ -499,6 +503,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"ignore_auth_resp",
#endif /* CONFIG_TESTING_OPTIONS */
"relative_rssi", "relative_band_adjust",
+ "extended_key_id",
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -585,12 +590,13 @@ static char ** wpa_cli_complete_get(const char *str, int pos)
"wps_nfc_dev_pw_id", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"dtim_period", "beacon_int", "ignore_old_scan_res",
- "scan_cur_freq", "sched_scan_interval",
+ "scan_cur_freq", "scan_res_valid_for_connect",
+ "sched_scan_interval",
"sched_scan_start_delay",
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim"
+ "reassoc_same_bss_optim", "extended_key_id"
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -1284,9 +1290,10 @@ static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_cli_cmd_bssid_ignore(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
+ return wpa_cli_cmd(ctrl, "BSSID_IGNORE", 0, argc, argv);
}
@@ -1299,7 +1306,7 @@ static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+ return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv);
}
@@ -1402,11 +1409,11 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
static const char *network_fields[] = {
- "ssid", "scan_ssid", "bssid", "bssid_blacklist",
- "bssid_whitelist", "psk", "proto", "key_mgmt",
+ "ssid", "scan_ssid", "bssid", "bssid_ignore",
+ "bssid_accept", "psk", "proto", "key_mgmt",
"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
"freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
- "vht_center_freq2", "ht",
+ "vht_center_freq2", "ht", "edmg",
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -1427,22 +1434,19 @@ static const char *network_fields[] = {
#ifdef IEEE8021X_EAPOL
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_MESH
- "mode", "no_auto_peer", "mesh_rssi_threshold",
-#else /* CONFIG_MESH */
"mode",
-#endif /* CONFIG_MESH */
"proactive_key_caching", "disabled", "id_str",
-#ifdef CONFIG_IEEE80211W
"ieee80211w",
-#endif /* CONFIG_IEEE80211W */
"mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
+ "no_auto_peer", "mesh_rssi_threshold",
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "wpa_deny_ptk0_rekey",
+ "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
@@ -1459,6 +1463,9 @@ static const char *network_fields[] = {
"vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
"vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ "disable_he",
+#endif /* CONFIG_HE_OVERRIDES */
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
@@ -1702,15 +1709,25 @@ static char ** wpa_cli_complete_bss(const char *str, int pos)
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- if (argc < 1 || argc > 2) {
- printf("Invalid GET_CAPABILITY command: need either one or "
- "two arguments\n");
+ if (argc < 1 || argc > 3) {
+ printf("Invalid GET_CAPABILITY command: need at least one argument and max three arguments\n");
return -1;
}
- if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
- printf("Invalid GET_CAPABILITY command: second argument, "
- "if any, must be 'strict'\n");
+ if (argc > 1 && os_strcmp(argv[0], "key_mgmt") != 0 &&
+ os_strncmp(argv[1], "iftype=", 7) == 0) {
+ printf("Invalid GET_CAPABILITY command: 'iftype=' param is allowed only for 'key_mgmt'\n");
+ return -1;
+ }
+
+ if (argc == 2 && os_strcmp(argv[1], "strict") != 0 &&
+ os_strncmp(argv[1], "iftype=", 7) != 0) {
+ printf("Invalid GET_CAPABILITY command: the second argument, if any, must be 'strict' OR 'iftype=<iftype_name>'\n");
+ return -1;
+ }
+
+ if (argc == 3 && os_strcmp(argv[2], "strict") != 0) {
+ printf("Invalid GET_CAPABILITY command: the third argument, if any, must be 'strict'\n");
return -1;
}
@@ -1737,7 +1754,13 @@ static char ** wpa_cli_complete_get_capability(const char *str, int pos)
"acs",
#endif /* CONFIG_ACS */
};
+ const char *iftypes[] = {
+ "iftype=STATION", "iftype=AP", "iftype=P2P_CLIENT",
+ "iftype=P2P_GO", "iftype=AP_VLAN", "iftype=IBSS", "iftype=NAN",
+ "iftype=P2P_DEVICE", "iftype=MESH",
+ };
int i, num_fields = ARRAY_SIZE(fields);
+ int num_iftypes = ARRAY_SIZE(iftypes);
char **res = NULL;
if (arg == 1) {
@@ -1751,6 +1774,21 @@ static char ** wpa_cli_complete_get_capability(const char *str, int pos)
}
}
if (arg == 2) {
+ /* the second argument can be "iftype=<iftype_name>" OR
+ * "strict" */
+ res = os_calloc(num_iftypes + 2, sizeof(char *));
+ if (!res)
+ return NULL;
+ res[0] = os_strdup("strict");
+ if (!res[0])
+ return res;
+ for (i = 0; i < num_iftypes; i++) {
+ res[i + 1] = os_strdup(iftypes[i]);
+ if (!res[i + 1])
+ return res;
+ }
+ }
+ if (arg == 3) {
res = os_calloc(1 + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -1783,7 +1821,7 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- printf("Connected to interface '%s.\n", ctrl_ifname);
+ printf("Connected to interface '%s'.\n", ctrl_ifname);
} else {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
@@ -2888,6 +2926,20 @@ static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TWT_TEARDOWN", 0, argc, argv);
+}
+
+
static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "ERP_FLUSH");
@@ -2959,6 +3011,13 @@ static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -3021,9 +3080,146 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int wpa_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
+}
+
+
+static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+ char buf[512], *pos, *bssid = NULL, *freq = NULL, *level = NULL,
+ *flags = NULL, *ssid = NULL;
+ size_t len;
+ int ret, id = -1;
+
+ if (!ctrl_conn)
+ return -1;
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+ wpa_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ if (os_memcmp(buf, "FAIL", 4) == 0)
+ return -1;
+
+ pos = buf;
+ while (*pos != '\0') {
+ if (str_starts(pos, "id="))
+ id = atoi(pos + 3);
+ if (str_starts(pos, "bssid="))
+ bssid = pos + 6;
+ if (str_starts(pos, "freq="))
+ freq = pos + 5;
+ if (str_starts(pos, "level="))
+ level = pos + 6;
+ if (str_starts(pos, "flags="))
+ flags = pos + 6;
+ if (str_starts(pos, "ssid="))
+ ssid = pos + 5;
+
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ *pos++ = '\0';
+ }
+ if (id != -1)
+ printf("%s\t%s\t%s\t%s\t%s\n", bssid ? bssid : "N/A",
+ freq ? freq : "N/A", level ? level : "N/A",
+ flags ? flags : "N/A", ssid ? ssid : "N/A");
+ return id;
+}
+
+
+static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[64];
+ int id = -1;
+ unsigned int mask;
+
+ printf("bssid / frequency / signal level / flags / ssid\n");
+
+ mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ |
+ WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID;
+ do {
+ if (id < 0)
+ os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x",
+ mask);
+ else
+ os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x",
+ id, mask);
+ id = wpa_ctrl_command_bss(ctrl, cmd);
+ } while (id >= 0);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PASN
+
+static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv);
+}
+
+static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PTKSA_CACHE_LIST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pasn_deauth(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PASN_DEAUTH", 1, argc, argv);
+}
+
+#endif /* CONFIG_PASN */
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3150,11 +3346,15 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
- { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
+ { "bssid_ignore", wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss,
cli_cmd_flag_none,
- "<BSSID> = add a BSSID to the blacklist\n"
- "blacklist clear = clear the blacklist\n"
- "blacklist = display the blacklist" },
+ "<BSSID> = add a BSSID to the list of temporarily ignored BSSs\n"
+ "bssid_ignore clear = clear the list of temporarily ignored BSSIDs\n"
+ "bssid_ignore = display the list of temporarily ignored BSSIDs" },
+ { "blacklist", /* deprecated alias for bssid_ignore */
+ wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "= deprecated alias for bssid_ignore" },
{ "log_level", wpa_cli_cmd_log_level, NULL,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
@@ -3626,6 +3826,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
"[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
},
+ { "twt_setup",
+ wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
+ "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>] [min_twt=<Min TWT>] [setup_cmd=<setup-cmd>] [twt=<u64>] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=<twt chanel id>] [control=<control-u8>] = Send TWT Setup frame"
+ },
+ { "twt_teardown",
+ wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
+ "[flags=<value>] = Send TWT Teardown frame"
+ },
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
"= flush ERP keys" },
{ "mac_rand_scan",
@@ -3657,6 +3865,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL,
cli_cmd_flag_none,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL,
+ cli_cmd_flag_none,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none,
@@ -3682,7 +3893,37 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL,
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_controller_start", wpa_cli_cmd_dpp_controller_start, NULL,
+ cli_cmd_flag_none,
+ "[tcp_port=<port>] [role=..] = start DPP controller" },
+ { "dpp_controller_stop", wpa_cli_cmd_dpp_controller_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP controller" },
+ { "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL,
+ cli_cmd_flag_none,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+ "= list all BSS entries (scan results)" },
+#ifdef CONFIG_PASN
+ { "pasn_auth_start", wpa_cli_cmd_pasn_auth_start, NULL,
+ cli_cmd_flag_none,
+ "bssid=<BSSID> akmp=<WPA key mgmt> cipher=<WPA cipher> group=<group> nid=<network id> = Start PASN authentication" },
+ { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL,
+ cli_cmd_flag_none,
+ "= Stop PASN authentication" },
+ { "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL,
+ cli_cmd_flag_none,
+ "= Get the PTKSA Cache" },
+ { "pasn_deauth", wpa_cli_cmd_pasn_deauth, NULL,
+ cli_cmd_flag_none,
+ "bssid=<BSSID> = Remove PASN PTKSA state" },
+#endif /* CONFIG_PASN */
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -4007,6 +4248,12 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_ACTIVE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_OVERLAP)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_PIN_ACTIVE)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_CANCEL)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_TIMEOUT)) {
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_FAIL)) {
@@ -4041,7 +4288,8 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
- wpa_cli_quit = 1;
+ if (!reconnect)
+ wpa_cli_quit = 1;
}
}
@@ -4233,6 +4481,10 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
if (wpa_ctrl_pending(ctrl) < 0) {
printf("Connection to wpa_supplicant lost - trying to "
"reconnect\n");
+ if (reconnect) {
+ eloop_terminate();
+ return;
+ }
wpa_cli_reconnect();
}
}
@@ -4580,6 +4832,8 @@ static void wpa_cli_cleanup(void)
static void wpa_cli_terminate(int sig, void *ctx)
{
eloop_terminate();
+ if (reconnect)
+ wpa_cli_quit = 1;
}
@@ -4610,8 +4864,11 @@ static char * wpa_cli_get_default_ifname(void)
if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
continue;
#endif /* _DIRENT_HAVE_D_TYPE */
+ /* Skip current/previous directory and special P2P Device
+ * interfaces. */
if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
+ os_strcmp(dent->d_name, "..") == 0 ||
+ os_strncmp(dent->d_name, "p2p-dev-", 8) == 0)
continue;
printf("Selected interface '%s'\n", dent->d_name);
ifname = os_strdup(dent->d_name);
@@ -4657,7 +4914,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "a:Bg:G:hi:p:P:s:v");
+ c = getopt(argc, argv, "a:Bg:G:hi:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -4689,6 +4946,9 @@ int main(int argc, char *argv[])
case 'P':
pid_file = optarg;
break;
+ case 'r':
+ reconnect = 1;
+ break;
case 's':
client_socket_dir = optarg;
break;
@@ -4714,7 +4974,22 @@ int main(int argc, char *argv[])
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
- if (interactive) {
+ if (reconnect && action_file && ctrl_ifname) {
+ while (!wpa_cli_quit) {
+ if (ctrl_conn)
+ wpa_cli_action(ctrl_conn);
+ else
+ os_sleep(1, 0);
+ wpa_cli_close_connection();
+ wpa_cli_open_connection(ctrl_ifname, 0);
+ if (ctrl_conn) {
+ if (wpa_ctrl_attach(ctrl_conn) != 0)
+ wpa_cli_close_connection();
+ else
+ wpa_cli_attached = 1;
+ }
+ }
+ } else if (interactive) {
wpa_cli_interactive();
} else {
if (!global &&
diff --git a/contrib/wpa/wpa_supplicant/wpa_passphrase.c b/contrib/wpa/wpa_supplicant/wpa_passphrase.c
index adca1cce13ee..538997e62580 100644
--- a/contrib/wpa/wpa_supplicant/wpa_passphrase.c
+++ b/contrib/wpa/wpa_supplicant/wpa_passphrase.c
@@ -31,9 +31,9 @@ int main(int argc, char *argv[])
if (argc > 2) {
passphrase = argv[2];
} else {
- printf("# reading passphrase from stdin\n");
+ fprintf(stderr, "# reading passphrase from stdin\n");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
- printf("Failed to read passphrase\n");
+ fprintf(stderr, "Failed to read passphrase\n");
return 1;
}
buf[sizeof(buf) - 1] = '\0';
@@ -50,11 +50,11 @@ int main(int argc, char *argv[])
len = os_strlen(passphrase);
if (len < 8 || len > 63) {
- printf("Passphrase must be 8..63 characters\n");
+ fprintf(stderr, "Passphrase must be 8..63 characters\n");
return 1;
}
if (has_ctrl_char((u8 *) passphrase, len)) {
- printf("Invalid passphrase character\n");
+ fprintf(stderr, "Invalid passphrase character\n");
return 1;
}
diff --git a/contrib/wpa/wpa_supplicant/wpa_priv.c b/contrib/wpa/wpa_supplicant/wpa_priv.c
index b3ad45eca516..c5d7168690f7 100644
--- a/contrib/wpa/wpa_supplicant/wpa_priv.c
+++ b/contrib/wpa/wpa_supplicant/wpa_priv.c
@@ -391,6 +391,7 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
{
struct privsep_cmd_set_key *params;
int res;
+ struct wpa_driver_set_key_params p;
if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
return;
@@ -402,14 +403,19 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
params = buf;
- res = iface->driver->set_key(iface->ifname, iface->drv_priv,
- params->alg,
- params->addr, params->key_idx,
- params->set_tx,
- params->seq_len ? params->seq : NULL,
- params->seq_len,
- params->key_len ? params->key : NULL,
- params->key_len);
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = iface->ifname;
+ p.alg = params->alg;
+ p.addr = params->addr;
+ p.key_idx = params->key_idx;
+ p.set_tx = params->set_tx;
+ p.seq = params->seq_len ? params->seq : NULL;
+ p.seq_len = params->seq_len;
+ p.key = params->key_len ? params->key : NULL;
+ p.key_len = params->key_len;
+ p.key_flag = params->key_flag;
+
+ res = iface->driver->set_key(iface->drv_priv, &p);
wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
}
@@ -598,7 +604,7 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
dst_addr = buf;
- os_memcpy(&proto, buf + ETH_ALEN, 2);
+ os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
@@ -607,7 +613,8 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
res = l2_packet_send(iface->l2[idx], dst_addr, proto,
- buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ (unsigned char *) buf + ETH_ALEN + 2,
+ len - ETH_ALEN - 2);
wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -1183,14 +1190,15 @@ static void wpa_priv_fd_workaround(void)
static void usage(void)
{
- printf("wpa_priv v" VERSION_STR "\n"
+ printf("wpa_priv v%s\n"
"Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
" wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] "
"<driver:ifname> \\\n"
- " [driver:ifname ...]\n");
+ " [driver:ifname ...]\n",
+ VERSION_STR);
}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
index 31b1bc8e5c80..47b542e91dd7 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
@@ -41,9 +41,10 @@
#include "common/hw_features_common.h"
#include "common/gas_server.h"
#include "common/dpp.h"
+#include "common/ptksa_cache.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
@@ -125,8 +126,12 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -139,11 +144,15 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
set = 1;
wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
- ssid->wep_key[i], ssid->wep_key_len[i]);
+ ssid->wep_key[i], ssid->wep_key_len[i],
+ i == ssid->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX);
}
return set;
}
+#endif /* CONFIG_WEP */
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -197,7 +206,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
}
@@ -213,7 +223,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
@@ -281,7 +291,7 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
- wpa_blacklist_del(wpa_s, wpa_s->bssid);
+ wpa_bssid_ignore_del(wpa_s, wpa_s->bssid);
os_free(wpa_s->last_con_fail_realm);
wpa_s->last_con_fail_realm = NULL;
wpa_s->last_con_fail_realm_len = 0;
@@ -310,14 +320,14 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
* per-BSSID EAPOL authentication.
*/
eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
return;
}
#endif /* CONFIG_IBSS_RSN */
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
@@ -389,7 +399,9 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
+#endif /* CONFIG_WEP */
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -399,11 +411,15 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
+#ifdef CONFIG_WEP
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] > 5) {
wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
@@ -415,16 +431,15 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
break;
}
}
+#endif /* CONFIG_WEP */
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -446,16 +461,22 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
}
+static void remove_bss_tmp_disallowed_entry(struct wpa_supplicant *wpa_s,
+ struct wpa_bss_tmp_disallowed *bss)
+{
+ eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
+ dl_list_del(&bss->list);
+ os_free(bss);
+}
+
+
void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
{
struct wpa_bss_tmp_disallowed *bss, *prev;
dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
- struct wpa_bss_tmp_disallowed, list) {
- eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
- dl_list_del(&bss->list);
- os_free(bss);
- }
+ struct wpa_bss_tmp_disallowed, list)
+ remove_bss_tmp_disallowed_entry(wpa_s, bss);
}
@@ -472,6 +493,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
}
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ return;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+ wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+ struct driver_signal_override *dso;
+
+ while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+ struct driver_signal_override, list))) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -495,6 +541,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
wpa_s->last_assoc_req_wpa_ie = NULL;
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ wpa_s->rsnxe_override_assoc = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -525,9 +580,15 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wmm_ac_clear_saved_tspecs(wpa_s);
pmksa_candidate_free(wpa_s->wpa);
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
wpa_bss_deinit(wpa_s);
@@ -541,6 +602,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
wpas_wps_deinit(wpa_s);
@@ -677,6 +739,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
dpp_global_deinit(wpa_s->dpp);
wpa_s->dpp = NULL;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
}
@@ -690,25 +756,24 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- int i, max;
-
-#ifdef CONFIG_IEEE80211W
- max = 6;
-#else /* CONFIG_IEEE80211W */
- max = 4;
-#endif /* CONFIG_IEEE80211W */
+ int i, max = 6;
/* MLME-DELETEKEYS.request */
for (i = 0; i < max; i++) {
if (wpa_s->keys_cleared & BIT(i))
continue;
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ NULL, 0, KEY_FLAG_GROUP);
}
- if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
+ if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
!is_zero_ether_addr(addr)) {
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
- 0);
+ if (!(wpa_s->keys_cleared & BIT(0)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ if (!(wpa_s->keys_cleared & BIT(15)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -755,7 +820,22 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
#ifdef CONFIG_BGSCAN
-static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan_ssid) {
+ bgscan_deinit(wpa_s);
+ wpa_s->bgscan_ssid = NULL;
+ }
+}
+
+
+/**
+ * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
+ * @wpa_s: Pointer to the wpa_supplicant data
+ *
+ * Stop, start, or reconfigure the scan parameters depending on the method.
+ */
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
{
const char *name;
@@ -763,12 +843,12 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
name = wpa_s->current_ssid->bgscan;
else
name = wpa_s->conf->bgscan;
- if (name == NULL || name[0] == '\0')
+ if (!name || name[0] == '\0') {
+ wpa_supplicant_stop_bgscan(wpa_s);
return;
+ }
if (wpas_driver_bss_selection(wpa_s))
return;
- if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
- return;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
return;
@@ -798,15 +878,6 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
wpa_s->bgscan_ssid = NULL;
}
-
-static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->bgscan_ssid != NULL) {
- bgscan_deinit(wpa_s);
- wpa_s->bgscan_ssid = NULL;
- }
-}
-
#endif /* CONFIG_BGSCAN */
@@ -845,6 +916,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state)
{
enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ bool update_fils_connect_params = false;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -927,8 +1001,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
fils_hlp_sent ? " FILS_HLP_SENT" : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
wpa_s->new_connection = 0;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
@@ -942,8 +1015,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- wpas_update_fils_connect_params(wpa_s);
+ update_fils_connect_params = true;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -956,8 +1033,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_s->wpa_state = state;
#ifdef CONFIG_BGSCAN
- if (state == WPA_COMPLETED)
- wpa_supplicant_start_bgscan(wpa_s);
+ if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+ wpa_supplicant_reset_bgscan(wpa_s);
else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
@@ -983,7 +1060,15 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (update_fils_connect_params)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
}
@@ -1020,13 +1105,19 @@ static void wpa_supplicant_terminate(int sig, void *signal_ctx)
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
{
enum wpa_states old_state = wpa_s->wpa_state;
+ enum wpa_states new_state;
+
+ if (old_state == WPA_SCANNING)
+ new_state = WPA_SCANNING;
+ else
+ new_state = WPA_DISCONNECTED;
wpa_s->pairwise_cipher = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ wpa_supplicant_set_state(wpa_s, new_state);
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -1073,8 +1164,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
os_strcmp(conf->ctrl_interface,
wpa_s->conf->ctrl_interface) != 0);
- if (reconf_ctrl && wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ if (reconf_ctrl) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL;
}
@@ -1097,7 +1188,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
* Clear forced success to clear EAP state for next
* authentication.
*/
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
}
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
@@ -1121,6 +1212,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+ wpa_bssid_ignore_clear(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
return 0;
}
@@ -1179,7 +1271,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1187,7 +1278,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
"reject");
return -1;
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -1224,15 +1314,17 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
- int sel, proto;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ int sel, proto, sae_pwe;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1312,7 +1404,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
ie.mgmt_group_cipher = 0;
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (ssid->group_mgmt_cipher &
@@ -1331,7 +1422,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.mgmt_group_cipher =
WPA_CIPHER_AES_128_CMAC;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
@@ -1351,12 +1441,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d proto %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
ie.mgmt_group_cipher);
}
-#endif /* CONFIG_IEEE80211W */
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1367,7 +1455,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1403,17 +1493,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
- ie.key_mgmt, ssid->key_mgmt, sel);
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+ WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+ sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT FT/802.1X-SHA384");
@@ -1456,7 +1552,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
if (!ssid->ft_eap_pmksa_caching &&
@@ -1486,7 +1583,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1495,7 +1591,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1526,7 +1621,13 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "RSN: Management frame protection required but the selected AP does not enable it");
+ return -1;
+ }
+
sel = ie.mgmt_group_cipher;
if (ssid->group_mgmt_cipher)
sel &= ssid->group_mgmt_cipher;
@@ -1560,21 +1661,81 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->mgmt_group_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
+ sae_pwe = wpa_s->conf->sae_pwe;
+ if (ssid->sae_password_id && sae_pwe != 3)
+ sae_pwe = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_SAE_PK
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
+ wpa_s->ft_rsnxe_used);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
+ wpa_s->oci_freq_override_eapol);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ wpa_s->oci_freq_override_fils_assoc);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Extended Key ID is only supported in infrastructure BSS so far */
+ if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+ (ssid->proto & WPA_PROTO_RSN) &&
+ ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+ int use_ext_key_id = 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "WPA: Enable Extended Key ID support");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
+ wpa_s->conf->extended_key_id);
+ if (bss_rsn &&
+ wpa_s->conf->extended_key_id &&
+ wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
+ (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+ use_ext_key_id = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
+ use_ext_key_id);
+ } else {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
+ }
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
/* Use PMK from DPP network introduction (PMKSA entry) */
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#ifdef CONFIG_DPP2
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DPP_PFS, ssid->dpp_pfs);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
@@ -1691,6 +1852,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+ if (ssid->mode != WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with reconnect");
+ wpa_s->deny_ptk0_rekey = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
+ } else {
+ wpa_s->deny_ptk0_rekey = 0;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
+ }
+
return 0;
}
@@ -1711,7 +1886,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (!wpa_s->conf->disable_btm)
+ if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
*pos |= 0x08; /* Bit 19 - BSS Transition */
#endif /* CONFIG_WNM */
break;
@@ -1755,6 +1930,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1762,7 +1940,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 10, i;
+ u8 len = 11, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -1918,6 +2096,79 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if (!password ||
+ (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ !sae_pk_valid_password(password)) ||
+ conf->sae_pwe == 3) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_sae_rejected_groups) {
+ int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+ for (i = 0; groups[i]; i++) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Indicate rejection of an extra SAE group %d",
+ groups[i]);
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ groups[i]);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
+int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not restore permanent MAC address");
+ return -1;
+ }
+ wpa_s->mac_addr_changed = 0;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+ return 0;
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1935,6 +2186,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
int rand_style;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
/*
* If we are starting a new connection, any previously pending EAPOL
@@ -1948,6 +2200,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
else
rand_style = ssid->mac_addr;
+ wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
@@ -1964,6 +2217,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+ wpa_s_clear_sae_rejected(wpa_s);
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -1971,18 +2229,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
- if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not restore permanent MAC address");
- return;
- }
- wpa_s->mac_addr_changed = 0;
- if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not update MAC address information");
+ if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
return;
- }
- wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
}
wpa_s->last_ssid = ssid;
@@ -2034,10 +2282,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
wpa_s->current_bss = bss;
- wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->id);
- wpas_notify_mesh_group_started(wpa_s, ssid);
#else /* CONFIG_MESH */
wpa_msg(wpa_s, MSG_ERROR,
"mesh mode support not included in the build");
@@ -2061,10 +2305,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_TDLS
if (bss)
- wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
- bss->ie_len);
+ wpa_tdls_ap_ies(wpa_s->wpa, wpa_bss_ie_ptr(bss), bss->ie_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
@@ -2153,6 +2400,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
+ int is_24ghz;
freq->freq = ssid->frequency;
@@ -2204,8 +2452,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!mode)
return;
- /* HE can work without HT + VHT */
- freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+ freq->channel = channel;
+
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
@@ -2218,6 +2468,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!freq->ht_enabled)
return;
+ /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+ if (is_24ghz)
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+#ifdef CONFIG_HE_OVERRIDES
+ if (is_24ghz && ssid->disable_he)
+ freq->he_enabled = 0;
+#endif /* CONFIG_HE_OVERRIDES */
+
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return;
@@ -2239,8 +2497,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40) {
+#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht)
return;
+#endif /* CONFIG_VHT_OVERRIDES */
goto skip_ht40;
}
#endif /* CONFIG_HT_OVERRIDES */
@@ -2286,8 +2546,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
return;
}
- res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
- sec_chan->chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
switch (res) {
case 0:
/* Back to HT20 */
@@ -2338,6 +2597,9 @@ skip_ht40:
if (!vht_freq.vht_enabled)
return;
+ /* Enable HE with VHT for 5 GHz */
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(vht80); j++) {
if (freq->channel >= vht80[j] &&
@@ -2411,8 +2673,15 @@ skip_ht40:
#endif /* CONFIG_HT_OVERRIDES */
}
+#ifdef CONFIG_HE_OVERRIDES
+ if (ssid->disable_he) {
+ vht_freq.he_enabled = 0;
+ freq->he_enabled = 0;
+ }
+#endif /* CONFIG_HE_OVERRIDES */
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
- freq->channel, freq->ht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
@@ -2530,9 +2799,9 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif
-#ifdef CONFIG_SAE
- int sae_pmksa_cached = 0;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ int pmksa_cached = 0;
+#endif /* CONFIG_SAE || CONFIG_FILS */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2572,9 +2841,9 @@ static u8 * wpas_populate_assoc_ies(
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-#ifdef CONFIG_SAE
- sae_pmksa_cached = 1;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ pmksa_cached = 1;
+#endif /* CONFIG_SAE || CONFIG_FILS */
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2673,6 +2942,10 @@ static u8 * wpas_populate_assoc_ies(
if (mask)
*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ pmksa_cached) {
+ algs = WPA_AUTH_ALG_FILS;
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
@@ -2689,7 +2962,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_SAE
- if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
algs = WPA_AUTH_ALG_OPEN;
@@ -2728,7 +3001,7 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2815,7 +3088,7 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2876,8 +3149,16 @@ static u8 * wpas_populate_assoc_ies(
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
- ssid->dpp_netaccesskey) {
+ if (DPP_VERSION > 1 &&
+ wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+ ssid->dpp_netaccesskey &&
+ ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (!pmksa || !pmksa->dpp_pfs)
+ goto pfs_fail;
+
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
ssid->dpp_netaccesskey_len);
@@ -2930,6 +3211,54 @@ pfs_fail:
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
+ wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie);
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+ mscs_ie_len);
+ wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -2955,6 +3284,24 @@ pfs_fail:
}
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ os_memset(&params, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, &params, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -2971,18 +3318,127 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
if (!wpa_ie)
return;
- if (params.auth_alg != WPA_AUTH_ALG_FILS) {
- os_free(wpa_ie);
- return;
+ if (params.auth_alg == WPA_AUTH_ALG_FILS) {
+ wpa_s->auth_alg = params.auth_alg;
+ wpa_drv_update_connect_params(wpa_s, &params, mask);
}
- wpa_s->auth_alg = params.auth_alg;
- wpa_drv_update_connect_params(wpa_s, &params, mask);
os_free(wpa_ie);
}
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, false);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3018,10 +3474,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
- int use_crypt, ret, i, bssid_changed;
+ const u8 *edmg_ie_oper;
+ int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
+#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
u8 prev_bssid[ETH_ALEN];
@@ -3059,6 +3518,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
+
+ /* Starting new association, so clear the possibly used WPA IE from the
+ * previous association. */
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
+ wpa_s->mscs_setup_done = false;
+
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
+ if (!wpa_ie) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
if (bss &&
(!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
#ifdef CONFIG_IEEE80211R
@@ -3092,6 +3565,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ os_free(wpa_ie);
return;
#endif /* CONFIG_WPS */
} else {
@@ -3107,16 +3581,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_cancel_scan(wpa_s);
- /* Starting new association, so clear the possibly used WPA IE from the
- * previous association. */
- wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-
- wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
- if (!wpa_ie) {
- wpas_connect_work_done(wpa_s);
- return;
- }
-
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -3126,10 +3590,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
use_crypt = 0;
+#ifdef CONFIG_WEP
if (wpa_set_wep_keys(wpa_s, ssid)) {
use_crypt = 1;
wep_keys_set = 1;
}
+#endif /* CONFIG_WEP */
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
use_crypt = 0;
@@ -3201,6 +3667,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = wpa_bss_get_ie_ext(bss,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ &params.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3209,12 +3740,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
params.bg_scan_period = ssid->bg_scan_period;
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
}
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
@@ -3251,7 +3788,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.drop_unencrypted = use_crypt;
-#ifdef CONFIG_IEEE80211W
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3270,7 +3806,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
#endif /* CONFIG_OWE */
}
}
-#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
@@ -3293,6 +3828,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_P2P
/*
@@ -3321,6 +3859,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->current_ssid)
params.prev_bssid = prev_bssid;
+#ifdef CONFIG_SAE
+ params.sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
+
ret = wpa_drv_associate(wpa_s, &params);
os_free(wpa_ie);
if (ret < 0) {
@@ -3374,11 +3916,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
+#ifdef CONFIG_WEP
if (wep_keys_set &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
+#endif /* CONFIG_WEP */
if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
/*
@@ -3475,7 +4019,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_s->ifname);
wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
mconf->meshid_len, reason_code);
- wpa_supplicant_leave_mesh(wpa_s);
+ wpa_supplicant_leave_mesh(wpa_s, true);
}
#endif /* CONFIG_MESH */
@@ -3492,6 +4036,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_supplicant_clear_connection(wpa_s, addr);
}
+
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->own_reconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+
+}
+
+
static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -3602,6 +4155,52 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
/**
+ * wpa_supplicant_remove_all_networks - Remove all configured networks
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success (errors are currently ignored)
+ *
+ * This function performs the following operations:
+ * 1. Remove all networks.
+ * 2. Send network removal notifications.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ int id;
+
+ id = ssid->id;
+ ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
+ }
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -3763,9 +4362,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s_clear_sae_rejected(wpa_s);
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4177,7 +4779,15 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+ if (wpa_s->own_disconnect_req) {
+ wpa_printf(MSG_DEBUG,
+ "Drop received EAPOL frame as we are disconnecting");
+ return;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu",
+ MAC2STR(src_addr), len);
if (wpa_s->ignore_auth_resp) {
wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
return;
@@ -4303,16 +4913,23 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
- * Set portValid = TRUE here since we are going to skip 4-way
+ * Set portValid = true here since we are going to skip 4-way
* handshake processing which would normally set portValid. We
* need this to allow the EAPOL state machines to be completed
* without going through EAPOL-Key handshake.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
}
+static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
+{
+ return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
+ !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
+}
+
+
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
if ((!wpa_s->p2p_mgmt ||
@@ -4322,7 +4939,9 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s, 0);
+ wpas_eapol_needs_l2_packet(wpa_s) ?
+ wpa_supplicant_rx_eapol : NULL,
+ wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -4330,18 +4949,25 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
L2_PACKET_FILTER_PKTTYPE))
wpa_dbg(wpa_s, MSG_DEBUG,
"Failed to attach pkt_type filter");
+
+ if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to get own L2 address");
+ return -1;
+ }
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
}
- if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
- return -1;
- }
-
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+ wpas_wps_update_mac_addr(wpa_s);
+
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
return 0;
}
@@ -4372,6 +4998,65 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
}
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname)
+{
+ if (wpa_s->wpa_state > WPA_SCANNING)
+ return -EBUSY;
+
+ if (bridge_ifname &&
+ os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
+ return -EINVAL;
+
+ if (!bridge_ifname)
+ bridge_ifname = "";
+
+ if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
+ return 0;
+
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+
+ os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+
+ if (wpa_s->bridge_ifname[0]) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Receiving packets from bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
+ if (!wpa_s->l2_br) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to open l2_packet connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ goto fail;
+ }
+ }
+
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
+ goto fail;
+#endif /* CONFIG_TDLS */
+
+ return 0;
+fail:
+ wpa_s->bridge_ifname[0] = 0;
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt)
+ wpa_tdls_init(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+ return -EIO;
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -4393,7 +5078,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
- if (wpa_s->bridge_ifname[0]) {
+ if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init_bridge(
@@ -4467,9 +5152,13 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
wpa_s->parent = parent ? parent : wpa_s;
wpa_s->p2pdev = wpa_s->parent;
wpa_s->sched_scanning = 0;
+ wpa_s->setband_mask = WPA_SETBAND_AUTO;
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+ dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
return wpa_s;
}
@@ -4832,6 +5521,19 @@ void wpa_supplicant_apply_vht_overrides(
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_he = ssid->disable_he;
+}
+#endif /* CONFIG_HE_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -4995,7 +5697,7 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
static const u8 * wpas_fst_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -5009,7 +5711,7 @@ static const u8 * wpas_fst_get_peer_first(void *ctx,
static const u8 * wpas_fst_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return NULL;
}
@@ -5195,7 +5897,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
list) {
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5251,7 +5953,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
* rejected by kernel.
*/
if (os_strcmp(tmp->type, "scan") == 0 &&
- radio->external_scan_running &&
+ external_scan_running(radio) &&
(((struct wpa_driver_scan_params *)
tmp->ctx)->only_new_results ||
tmp->wpa_s->clear_driver_scan_cache))
@@ -5290,7 +5992,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
if (work->started)
return; /* already started and still in progress */
- if (wpa_s && wpa_s->radio->external_scan_running) {
+ if (wpa_s && external_scan_running(wpa_s->radio)) {
wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
return;
}
@@ -5386,6 +6088,10 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
wpa_s->ifname, radio->name);
dl_list_del(&wpa_s->radio_list);
radio_remove_works(wpa_s, NULL, 0);
+ /* If the interface that triggered the external scan was removed, the
+ * external scan is no longer running. */
+ if (wpa_s == radio->external_scan_req_interface)
+ radio->external_scan_req_interface = NULL;
wpa_s->radio = NULL;
if (!dl_list_empty(&radio->ifaces))
return; /* Interfaces remain for this radio */
@@ -5539,6 +6245,8 @@ next_driver:
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
const char *pos;
+ int level = MSG_ERROR;
+
pos = driver ? os_strchr(driver, ',') : NULL;
if (pos) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
@@ -5546,8 +6254,12 @@ next_driver:
driver = pos + 1;
goto next_driver;
}
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
+
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
+ level = MSG_DEBUG;
+#endif /* CONFIG_MATCH_IFACE */
+ wpa_msg(wpa_s, level, "Failed to initialize driver interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
@@ -5692,6 +6404,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+#ifdef CONFIG_MATCH_IFACE
+ wpa_s->matched = iface->matched;
+#endif /* CONFIG_MATCH_IFACE */
if (iface->bridge_ifname) {
if (os_strlen(iface->bridge_ifname) >=
@@ -5705,8 +6420,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
}
/* RSNA Supplicant Key Management - INITIALIZE */
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* Initialize driver interface and register driver event handler before
* L2 receive handler so that association events are processed before
@@ -5773,8 +6488,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_flags2 = capa.flags2;
wpa_s->drv_enc = capa.enc;
- wpa_s->drv_smps_modes = capa.smps_modes;
wpa_s->drv_rrm_flags = capa.rrm_flags;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
@@ -5951,7 +6666,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
hs20_init(wpa_s);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (wpa_s->conf->oce) {
+ if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
wpa_s->enable_oce = OCE_STA;
@@ -5998,11 +6713,21 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ /*
+ * Don't deauthenticate if WoWLAN is enable and not explicitly
+ * been configured to disconnect.
+ */
+ if (!wpa_drv_get_wowlan(wpa_s) ||
+ wpa_s->conf->wowlan_disconnect_on_deinit) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_clear_keys(wpa_s, NULL);
+ wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_clear_keys(wpa_s, NULL);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+ }
}
wpa_supplicant_cleanup(wpa_s);
@@ -6031,14 +6756,12 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
if (terminate)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
+ wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
- wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
wpa_s->ifmsh = NULL;
}
#endif /* CONFIG_MESH */
@@ -6049,6 +6772,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
@@ -6076,6 +6800,10 @@ struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
if (!iface)
return NULL;
*iface = *miface;
+ if (!miface->ifname)
+ iface->matched = WPA_IFACE_MATCHED_NULL;
+ else
+ iface->matched = WPA_IFACE_MATCHED;
iface->ifname = ifname;
return iface;
}
@@ -6108,10 +6836,8 @@ static int wpa_supplicant_match_existing(struct wpa_global *global)
continue;
iface = wpa_supplicant_match_iface(global, ifi->if_name);
if (iface) {
- wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ wpa_supplicant_add_iface(global, iface, NULL);
os_free(iface);
- if (wpa_s)
- wpa_s->matched = 1;
}
}
@@ -6373,7 +7099,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
- else
+ if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
@@ -6441,7 +7167,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
- wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+ wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
@@ -6632,6 +7358,18 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
wpa_supplicant_set_default_scan_ies(wpa_s);
+#ifdef CONFIG_BGSCAN
+ /*
+ * We default to global bgscan parameters only when per-network bgscan
+ * parameters aren't set. Only bother resetting bgscan parameters if
+ * this is the case.
+ */
+ if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
+ wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -6672,7 +7410,7 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
continue;
if (bss->ssid_len == cbss->ssid_len &&
os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
- wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+ !wpa_bssid_ignore_is_listed(wpa_s, bss->bssid)) {
add_freq(freqs, &num_freqs, bss->freq);
if (num_freqs == max_freqs)
break;
@@ -6702,10 +7440,10 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
/*
- * There is no point in blacklisting the AP if this event is
+ * There is no point in ignoring the AP temporarily if this event is
* generated based on local request to disconnect.
*/
- if (wpa_s->own_disconnect_req) {
+ if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
wpa_s->own_disconnect_req = 0;
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore connection failure due to local request to disconnect");
@@ -6719,17 +7457,13 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
/*
- * Add the failed BSSID into the blacklist and speed up next scan
+ * Add the failed BSSID into the ignore list and speed up next scan
* attempt if there could be other APs that could accept association.
- * The current blacklist count indicates how many times we have tried
- * connecting to this AP and multiple attempts mean that other APs are
- * either not available or has already been tried, so that we can start
- * increasing the delay here to avoid constant scanning.
*/
- count = wpa_blacklist_add(wpa_s, bssid);
+ count = wpa_bssid_ignore_add(wpa_s, bssid);
if (count == 1 && wpa_s->current_bss) {
/*
- * This BSS was not in the blacklist before. If there is
+ * This BSS was not in the ignore list before. If there is
* another BSS available for the same ESS, we should try that
* next. Otherwise, we may as well try this one once more
* before allowing other, likely worse, ESSes to be considered.
@@ -6738,7 +7472,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
if (freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
"has been seen; try it next");
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
/*
* On the next scan, go through only the known channels
* used in this ESS based on previous scans to speed up
@@ -6749,19 +7483,19 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
}
- /*
- * Add previous failure count in case the temporary blacklist was
- * cleared due to no other BSSes being available.
- */
- count += wpa_s->extra_blacklist_count;
+ wpa_s->consecutive_conn_failures++;
- if (count > 3 && wpa_s->current_ssid) {
+ if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
wpas_auth_failed(wpa_s, "CONN_FAILED");
}
-
- switch (count) {
+ /*
+ * Multiple consecutive connection failures mean that other APs are
+ * either not available or have already been tried, so we can start
+ * increasing the delay here to avoid constant scanning.
+ */
+ switch (wpa_s->consecutive_conn_failures) {
case 1:
timeout = 100;
break;
@@ -6779,8 +7513,9 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
- "ms", count, timeout);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Consecutive connection failures: %d --> request scan in %d ms",
+ wpa_s->consecutive_conn_failures, timeout);
/*
* TODO: if more than one possible AP is available in scan results,
@@ -6795,6 +7530,46 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
#ifdef CONFIG_FILS
+
+void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+
+ /* Clear the PMKSA cache entry if FILS authentication was rejected.
+ * Check for ERP keys existing to limit when this can be done since
+ * the rejection response is not protected and such triggers should
+ * really not allow internal state to be modified unless required to
+ * avoid significant issues in functionality. In addition, drop
+ * externally configure PMKSA entries even without ERP keys since it
+ * is possible for an external component to add PMKSA entries for FILS
+ * authentication without restoring previously generated ERP keys.
+ *
+ * In this case, this is needed to allow recovery from cases where the
+ * AP or authentication server has dropped PMKSAs and ERP keys. */
+ if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt))
+ return;
+
+ if (eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) != 0 ||
+ !realm) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "FILS: Drop external PMKSA cache entry");
+ wpa_sm_aborted_external_cached(wpa_s->wpa);
+ wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid);
+ return;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+}
+
+
void fils_connection_failure(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -6869,8 +7644,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- str_clear_free(eap->pin);
- eap->pin = os_strdup(value);
+ str_clear_free(eap->cert.pin);
+ eap->cert.pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6884,8 +7659,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- str_clear_free(eap->private_key_passwd);
- eap->private_key_passwd = os_strdup(value);
+ str_clear_free(eap->cert.private_key_passwd);
+ eap->cert.private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6930,8 +7705,10 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
unsigned int drv_enc;
+#endif /* CONFIG_WEP */
if (wpa_s->p2p_mgmt)
return 1; /* no normal network profiles on p2p_mgmt interface */
@@ -6942,6 +7719,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
if (ssid->disabled)
return 1;
+#ifdef CONFIG_WEP
if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
@@ -6959,6 +7737,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
continue;
return 1; /* invalid WEP key */
}
+#endif /* CONFIG_WEP */
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
@@ -6972,7 +7751,6 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
-#ifdef CONFIG_IEEE80211W
if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
!(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7001,9 +7779,6 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
- return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
}
@@ -7144,7 +7919,6 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
wpa_s->normal_scans = 0;
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
- wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->last_owe_group = 0;
@@ -7360,12 +8134,17 @@ int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode)
+ u16 num_modes, enum hostapd_hw_mode mode,
+ bool is_6ghz)
{
u16 i;
for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
+ (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
return &modes[i];
}
@@ -7373,6 +8152,22 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
+struct hostapd_hw_modes * get_mode_with_freq(struct hostapd_hw_modes *modes,
+ u16 num_modes, int freq)
+{
+ int i, j;
+
+ for (i = 0; i < num_modes; i++) {
+ for (j = 0; j < modes[i].num_channels; j++) {
+ if (freq == modes[i].channels[j].freq)
+ return &modes[i];
+ }
+ }
+
+ return NULL;
+}
+
+
static struct
wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
const u8 *bssid)
@@ -7405,7 +8200,7 @@ static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
ETH_ALEN);
num_bssid++;
}
- ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
os_free(bssids);
return ret;
}
@@ -7420,8 +8215,7 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) {
if (bss == tmp) {
- dl_list_del(&tmp->list);
- os_free(tmp);
+ remove_bss_tmp_disallowed_entry(wpa_s, tmp);
wpa_set_driver_tmp_disallow_list(wpa_s);
break;
}
@@ -7474,8 +8268,11 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
return 0;
if (disallowed->rssi_threshold != 0 &&
- bss->level > disallowed->rssi_threshold)
+ bss->level > disallowed->rssi_threshold) {
+ remove_bss_tmp_disallowed_entry(wpa_s, disallowed);
+ wpa_set_driver_tmp_disallow_list(wpa_s);
return 0;
+ }
return 1;
}
@@ -7542,3 +8339,87 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si)
+{
+ int res;
+
+ if (!wpa_s->driver->signal_poll)
+ return -1;
+
+ res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (res == 0) {
+ struct driver_signal_override *dso;
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(wpa_s->bssid, dso->bssid,
+ ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+ si->current_signal,
+ dso->si_current_signal,
+ si->avg_signal,
+ dso->si_avg_signal,
+ si->avg_beacon_signal,
+ dso->si_avg_beacon_signal,
+ si->current_noise,
+ dso->si_current_noise);
+ si->current_signal = dso->si_current_signal;
+ si->avg_signal = dso->si_avg_signal;
+ si->avg_beacon_signal = dso->si_avg_beacon_signal;
+ si->current_noise = dso->si_current_noise;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+ size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!wpa_s->driver->get_scan_results2)
+ return NULL;
+
+ scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+ struct driver_signal_override *dso;
+ struct wpa_scan_res *res = scan_res->res[idx];
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver scan signal level %d->%d for "
+ MACSTR,
+ res->level, dso->scan_level,
+ MAC2STR(res->bssid));
+ res->flags |= WPA_SCAN_QUAL_INVALID;
+ if (dso->scan_level < 0)
+ res->flags |= WPA_SCAN_LEVEL_DBM;
+ else
+ res->flags &= ~WPA_SCAN_LEVEL_DBM;
+ res->level = dso->scan_level;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return scan_res;
+}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
index f12b7b6c8ee9..e3ae77114680 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
@@ -1,7 +1,5 @@
##### Example wpa_supplicant configuration file ###############################
#
-# ***** Please check wpa_supplicant.conf(5) for details on these options *****
-#
# This file describes configuration file format and lists all available option.
# Please also take a look at simpler configuration examples in 'examples'
# subdirectory.
@@ -61,6 +59,19 @@
# DIR=/var/run/wpa_supplicant GROUP=0
# (group can be either group name or gid)
#
+# For UDP connections (default on Windows): The value will be ignored. This
+# variable is just used to select that the control interface is to be created.
+# The value can be set to, e.g., udp (ctrl_interface=udp)
+#
+# For Windows Named Pipe: This value can be used to set the security descriptor
+# for controlling access to the control interface. Security descriptor can be
+# set using Security Descriptor String Format (see http://msdn.microsoft.com/
+# library/default.asp?url=/library/en-us/secauthz/security/
+# security_descriptor_string_format.asp). The descriptor string needs to be
+# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
+# DACL (which will reject all connections). See README-Windows.txt for more
+# information about SDDL string format.
+#
ctrl_interface=/var/run/wpa_supplicant
# IEEE 802.1X/EAPOL version
@@ -83,11 +94,8 @@ eapol_version=1
# 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
# the currently enabled networks are found, a new network (IBSS or AP mode
# operation) may be initialized (if configured) (default)
-# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
-# parameters (e.g., WPA IE generation); this mode can also be used with
-# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers (including MACsec).
+# 0: This mode must only be used when using wired Ethernet drivers
+# (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -95,9 +103,10 @@ eapol_version=1
# the driver reports successful association; each network block should have
# explicit security policy (i.e., only one option in the lists) for
# key_mgmt, pairwise, group, proto variables
-#
-# For use in FreeBSD with the wlan module ap_scan must be set to 1.
-#
+# Note: ap_scan=0/2 should not be used with the nl80211 driver interface (the
+# current Linux interface). ap_scan=1 is the only option working with nl80211.
+# For finding networks using hidden SSID, scan_ssid=1 in the network block can
+# be used with nl80211.
# When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
# created immediately regardless of scan results. ap_scan=1 mode will first try
# to scan for existing networks and only if no matches with the enabled
@@ -299,6 +308,26 @@ fast_reauth=1
# by executing the WPS protocol.
#wps_priority=0
+# Device Provisioning Protocol (DPP) parameters
+#
+# How to process DPP configuration
+# 0 = report received configuration to an external program for
+# processing; do not generate any network profile internally (default)
+# 1 = report received configuration to an external program and generate
+# a network profile internally, but do not automatically connect
+# to the created (disabled) profile; the network profile id is
+# reported to external programs
+# 2 = report received configuration to an external program, generate
+# a network profile internally, try to connect to the created
+# profile automatically
+#dpp_config_processing=0
+#
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+#
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -337,7 +366,14 @@ fast_reauth=1
# Password (and passphrase, etc.) backend for external storage
# format: <backend name>[:<optional backend parameters>]
+# Test backend which stores passwords in memory. Should only be used for
+# development purposes.
#ext_password_backend=test:pw1=password|pw2=testing
+# File-based backend which reads passwords from a file. The parameter
+# identifies the file to read passwords from. The password file follows the
+# format of wpa_supplicant.conf and accepts simple `key=passphrase` formatted
+# passwords.
+#ext_password_backend=file:/path/to/passwords.conf
# Disable P2P functionality
@@ -393,6 +429,16 @@ fast_reauth=1
# since all implementations are required to support group 19.
#sae_groups=19 20 21
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
+#sae_pwe=0
+
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -419,6 +465,9 @@ fast_reauth=1
# 1: Scan current operating frequency if another VIF on the same radio
# is already associated.
+# Seconds to consider old scan results valid for association (default: 5)
+#scan_res_valid_for_connect=5
+
# MAC address policy default
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -442,6 +491,11 @@ fast_reauth=1
# 0 = use permanent MAC address
# 1 = use random MAC address
# 2 = like 1, but maintain OUI (with local admin bit set)
+# Note that this setting is ignored when a specific MAC address is needed for
+# a full protocol exchange that includes GAS, e.g., when going through a DPP
+# exchange that exposes the configured interface address as part of the DP
+# Public Action frame exchanges before using GAS. That same address is then used
+# during the GAS exchange as well to avoid breaking the protocol expectations.
#gas_rand_mac_addr=0
# Lifetime of GAS random MAC address in seconds (default: 60)
@@ -482,7 +536,7 @@ fast_reauth=1
#go_venue_group=7
#go_venue_type=1
-# Homogenous ESS identifier
+# Homogeneous ESS identifier
# If this is set, scans will be used to request response only from BSSes
# belonging to the specified Homogeneous ESS. This is used only if interworking
# is enabled.
@@ -763,6 +817,11 @@ fast_reauth=1
# Set BIT(1) to Enable OCE in STA-CFON mode
#oce=1
+# Extended Key ID support for Individually Addressed frames
+# 0 = force off: Do not use Extended Key ID (default)
+# 1 = auto: Activate Extended Key ID support if the driver supports it
+#extended_key_id=0
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -788,12 +847,22 @@ fast_reauth=1
# scan_ssid:
# 0 = do not scan this SSID with specific Probe Request frames (default)
# 1 = scan with SSID-specific Probe Request frames (this can be used to
-# find APs that hide (do not broadcast) SSID or use multiple SSIDs;
+# find APs that do not accept broadcast SSID or use multiple SSIDs;
# this will add latency to scanning, so enable this only when needed)
#
# bssid: BSSID (optional); if set, this network block is used only when
# associating with the AP using the configured BSSID
#
+# ignore_broadcast_ssid: SSID broadcast behavior
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+# broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+# with some clients that do not support empty SSID) and ignore probe
+# requests for broadcast SSID
+#
# priority: priority group (integer)
# By default, all networks will get same priority group (0). If some of the
# networks are more desirable, this field can be used to change the order in
@@ -804,7 +873,7 @@ fast_reauth=1
# policy, signal strength, etc.
# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
# using this priority to select the order for scanning. Instead, they try the
-# networks in the order that they are listed in the configuration file.
+# networks in the order that used in the configuration file.
#
# mode: IEEE 802.11 operation mode
# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
@@ -915,13 +984,15 @@ fast_reauth=1
# management frames) certification program are:
# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
-# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
#
# ocv: whether operating channel validation is enabled
# This is a countermeasure against multi-channel man-in-the-middle attacks.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
-# 1 = enabled
+# 1 = enabled if wpa_supplicant's SME in use. Otherwise enabled only when the
+# driver indicates support for operating channel validation.
#ocv=1
#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
@@ -1061,6 +1132,18 @@ fast_reauth=1
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# wpa_deny_ptk0_rekey: Workaround for PTK rekey issues
+# PTK0 rekeys (using only one Key ID value for pairwise keys) can degrade the
+# security and stability with some cards.
+# To avoid the issues wpa_supplicant can replace those PTK rekeys (including
+# EAP reauthentications) with fast reconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow problematic PTK0 rekeys
+#
# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
# Authenticator role in IBSS, or in AP and mesh modes.
@@ -1311,6 +1394,12 @@ fast_reauth=1
# certificate. See altsubject_match documentation for more details.
# domain_suffix_match2: Constraint for server domain name. See
# domain_suffix_match for more details.
+# ocsp2: See ocsp for more details.
+#
+# Separate machine credentials can be configured for EAP-TEAP Phase 2 with
+# "machine_" prefix (e.g., "machine_identity") in the configuration parameters.
+# See the parameters without that prefix for more details on the meaning and
+# format of each such parameter.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -1398,6 +1487,67 @@ fast_reauth=1
# 1-65535 = DH Group to use for FILS PFS
#fils_dh_group=0
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
+# Whether beacon protection is enabled
+# This depends on management frame protection (ieee80211w) being enabled and
+# beacon protection support indication from the driver.
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
+# OWE DH Group
+# 0: use default (19) first and then try all supported groups one by one if AP
+# rejects the selected group
+# 1-65535: DH Group to use for OWE
+# Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+# currently supported.
+#owe_group=0
+
+# OWE-only mode (disable transition mode)
+# 0: enable transition mode (allow connection to either OWE or open BSS)
+# 1 = disable transition mode (allow connection only with OWE)
+#owe_only=0
+
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all
+# OWE groups. This was supposed to change to SHA384 for group 20 and
+# SHA512 for group 21. This parameter can be used to enable older
+# behavior mainly for testing purposes. There is no impact to group 19
+# behavior, but if enabled, this will make group 20 and 21 cases use
+# SHA256-based PTK derivation which will not work with the updated
+# OWE implementation on the AP side.
+#owe_ptk_workaround=0
+
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode
+# in their network profiles when the network has completed transition
+# steps, i.e., once sufficiently large number of APs in the ESS have
+# been updated to support the more secure alternative. When this
+# indication is used, the stations are expected to automatically
+# disable transition mode and less secure security options. This
+# includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+# and only allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require
+# OWE)
+
+# SAE-PK mode
+# 0: automatic SAE/SAE-PK selection based on password; enable
+# transition mode (allow SAE authentication without SAE-PK)
+# 1: SAE-PK only (disable transition mode; allow SAE authentication
+# only with SAE-PK)
+# 2: disable SAE-PK (allow SAE authentication only without SAE-PK)
+#sae_pk=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1510,6 +1660,16 @@ fast_reauth=1
# Set to 1 to disable BSS transition management
#disable_btm=0
+# Enable EDMG capability in STA/AP mode, default value is false
+#enable_edmg=1
+
+# This value is used to configure the channel bonding feature.
+# Default value is 0.
+# Relevant only if enable_edmg is true
+# In AP mode it defines the EDMG channel to use for AP operation.
+# In STA mode it defines the EDMG channel for connection (if supported by AP).
+#edmg_channel=9
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
@@ -1860,12 +2020,12 @@ network={
key_mgmt=NONE
}
-# Example configuration blacklisting two APs - these will be ignored
+# Example configuration ignoring two APs - these will be ignored
# for this network.
network={
ssid="example"
psk="very secret passphrase"
- bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
+ bssid_ignore=02:11:22:33:44:55 02:22:aa:44:55:66
}
# Example configuration limiting AP selection to a specific set of APs;
@@ -1873,7 +2033,7 @@ network={
network={
ssid="example"
psk="very secret passphrase"
- bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
+ bssid_accept=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
}
# Example config file that will only scan on channel 36.
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
index 8a4bdf8cbc33..60acb53c5c38 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
@@ -14,6 +14,8 @@
#include "common/defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "crypto/sha384.h"
+#include "eapol_supp/eapol_supp_sm.h"
#include "wps/wps_defs.h"
#include "config_ssid.h"
#include "wmm_ac.h"
@@ -118,6 +120,18 @@ struct wpa_interface {
* interface that is not a network interface.
*/
int p2p_mgmt;
+
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * matched - Interface was matched rather than specified
+ *
+ */
+ enum {
+ WPA_IFACE_NOT_MATCHED,
+ WPA_IFACE_MATCHED_NULL,
+ WPA_IFACE_MATCHED
+ } matched;
+#endif /* CONFIG_MATCH_IFACE */
};
/**
@@ -280,6 +294,7 @@ struct wpa_global {
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
int cross_connection;
+ int p2p_long_listen; /* remaining time in long Listen state in ms */
struct wpa_freq_range_list p2p_disallow_freq;
struct wpa_freq_range_list p2p_go_avoid_freq;
enum wpa_conc_pref {
@@ -314,12 +329,23 @@ struct wpa_global {
struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
- unsigned int external_scan_running:1;
+ /** NULL if no external scan running. */
+ struct wpa_supplicant *external_scan_req_interface;
unsigned int num_active_works;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
+/**
+ * Checks whether an external scan is running on a given radio.
+ * @radio: Pointer to radio struct
+ * Returns: true if an external scan is running, false otherwise.
+ */
+static inline bool external_scan_running(struct wpa_radio *radio)
+{
+ return radio && radio->external_scan_req_interface;
+}
+
#define MAX_ACTIVE_WORKS 2
@@ -477,6 +503,79 @@ struct fils_hlp_req {
struct wpabuf *pkt;
};
+struct driver_signal_override {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ int si_current_signal;
+ int si_avg_signal;
+ int si_avg_beacon_signal;
+ int si_current_noise;
+ int scan_level;
+};
+
+struct robust_av_data {
+ u8 dialog_token;
+ enum scs_request_type request_type;
+ u8 up_bitmap;
+ u8 up_limit;
+ u32 stream_timeout;
+ u8 frame_classifier[48];
+ size_t frame_classifier_len;
+ bool valid_config;
+};
+
+#ifdef CONFIG_PASN
+
+struct pasn_fils {
+ u8 nonce[FILS_NONCE_LEN];
+ u8 anonce[FILS_NONCE_LEN];
+ u8 session[FILS_SESSION_LEN];
+ u8 erp_pmkid[PMKID_LEN];
+ bool completed;
+};
+
+struct wpas_pasn {
+ int akmp;
+ int cipher;
+ u16 group;
+ int freq;
+ size_t kdk_len;
+
+ u8 trans_seq;
+ u8 status;
+
+ u8 bssid[ETH_ALEN];
+ size_t pmk_len;
+ u8 pmk[PMK_LEN_MAX];
+ bool using_pmksa;
+
+ u8 hash[SHA384_MAC_LEN];
+
+ struct wpabuf *beacon_rsne_rsnxe;
+ struct wpa_ptk ptk;
+ struct crypto_ecdh *ecdh;
+
+ struct wpabuf *comeback;
+ u16 comeback_after;
+
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+#endif /* CONFIG_SAE */
+
+ struct wpa_ssid *ssid;
+
+#ifdef CONFIG_FILS
+ struct pasn_fils fils;
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_IEEE80211R
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+#endif /* CONFIG_IEEE80211R */
+};
+#endif /* CONFIG_PASN */
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -526,6 +625,7 @@ struct wpa_supplicant {
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
int reassociate; /* reassociation requested */
+ bool roam_in_progress; /* roam in progress */
unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
int disconnected; /* all connections disabled; i.e., do no reassociate
@@ -540,6 +640,7 @@ struct wpa_supplicant {
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
int pairwise_cipher;
+ int deny_ptk0_rekey;
int group_cipher;
int key_mgmt;
int wpa_proto;
@@ -556,7 +657,7 @@ struct wpa_supplicant {
struct wpa_ssid_value *disallow_aps_ssid;
size_t disallow_aps_ssid_count;
- enum set_band setband;
+ u32 setband_mask;
/* Preferred network for the next connection attempt */
struct wpa_ssid *next_ssid;
@@ -581,6 +682,7 @@ struct wpa_supplicant {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+ void (*scan_res_fail_handler)(struct wpa_supplicant *wpa_s);
struct dl_list bss; /* struct wpa_bss::list */
struct dl_list bss_id; /* struct wpa_bss::list_id */
size_t num_bss;
@@ -592,14 +694,16 @@ struct wpa_supplicant {
* results.
*/
struct wpa_bss **last_scan_res;
- unsigned int last_scan_res_used;
- unsigned int last_scan_res_size;
+ size_t last_scan_res_used;
+ size_t last_scan_res_size;
struct os_reltime last_scan;
const struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been
* removed */
struct wpa_sm *wpa;
+ struct ptksa_cache *ptksa;
+
struct eapol_sm *eapol;
struct ctrl_iface_priv *ctrl_iface;
@@ -614,6 +718,9 @@ struct wpa_supplicant {
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;
@@ -623,19 +730,10 @@ struct wpa_supplicant {
unsigned int keys_cleared; /* bitfield of key indexes that the driver is
* known not to be configured with a key */
- struct wpa_blacklist *blacklist;
+ struct wpa_bssid_ignore *bssid_ignore;
- /**
- * extra_blacklist_count - Sum of blacklist counts after last connection
- *
- * This variable is used to maintain a count of temporary blacklisting
- * failures (maximum number for any BSS) over blacklist clear
- * operations. This is needed for figuring out whether there has been
- * failures prior to the last blacklist clear operation which happens
- * whenever no other not-blacklisted BSS candidates are available. This
- * gets cleared whenever a connection has been established successfully.
- */
- int extra_blacklist_count;
+ /* Number of connection failures since last successful connection */
+ unsigned int consecutive_conn_failures;
/**
* scan_req - Type of the scan request
@@ -697,13 +795,18 @@ struct wpa_supplicant {
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
u8 next_scan_bssid[ETH_ALEN];
+ unsigned int next_scan_bssid_wildcard_ssid:1;
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
+ int *last_scan_freqs;
+ unsigned int num_last_scan_freqs;
+ unsigned int suitable_network;
+ unsigned int no_suitable_network;
u64 drv_flags;
+ u64 drv_flags2;
unsigned int drv_enc;
- unsigned int drv_smps_modes;
unsigned int drv_rrm_flags;
/*
@@ -735,7 +838,7 @@ struct wpa_supplicant {
struct wps_er *wps_er;
unsigned int wps_run;
struct os_reltime wps_pin_start_time;
- int blacklist_cleared;
+ bool bssid_ignore_cleared;
struct wpabuf *pending_eapol_rx;
struct os_reltime pending_eapol_rx_time;
@@ -752,6 +855,7 @@ struct wpa_supplicant {
unsigned int connection_ht:1;
unsigned int connection_vht:1;
unsigned int connection_he:1;
+ unsigned int disable_mbo_oce:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -805,6 +909,7 @@ struct wpa_supplicant {
u8 ext_auth_bssid[ETH_ALEN];
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -868,7 +973,6 @@ struct wpa_supplicant {
P2P_GROUP_INTERFACE_CLIENT
} p2p_group_interface;
struct p2p_group *p2p_group;
- int p2p_long_listen; /* remaining time in long Listen state in ms */
char p2p_pin[10];
int p2p_wps_method;
u8 p2p_auth_invite[ETH_ALEN];
@@ -922,6 +1026,7 @@ struct wpa_supplicant {
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_edmg:1;
unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
@@ -1049,6 +1154,7 @@ struct wpa_supplicant {
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
unsigned int own_disconnect_req:1;
+ unsigned int own_reconnect_req:1;
unsigned int ignore_post_flush_scan_res:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
@@ -1107,7 +1213,10 @@ struct wpa_supplicant {
unsigned int p2p_go_csa_on_inv:1;
unsigned int ignore_auth_resp:1;
unsigned int ignore_assoc_disallow:1;
+ unsigned int disable_sa_query:1;
unsigned int testing_resend_assoc:1;
+ unsigned int ignore_sae_h2e_only:1;
+ int ft_rsnxe_used;
struct wpabuf *sae_commit_override;
enum wpa_alg last_tk_alg;
u8 last_tk_addr[ETH_ALEN];
@@ -1115,6 +1224,18 @@ struct wpa_supplicant {
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
struct wpabuf *last_assoc_req_wpa_ie;
+ int *extra_sae_rejected_groups;
+ struct wpabuf *rsne_override_eapol;
+ struct wpabuf *rsnxe_override_assoc;
+ struct wpabuf *rsnxe_override_eapol;
+ struct dl_list drv_signal_override;
+ unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1215,9 +1336,10 @@ struct wpa_supplicant {
struct wpa_radio_work *dpp_listen_work;
unsigned int dpp_pending_listen_freq;
unsigned int dpp_listen_freq;
+ struct os_reltime dpp_listen_end;
u8 dpp_allowed_roles;
int dpp_qr_mutual;
- int dpp_netrole_ap;
+ int dpp_netrole;
int dpp_auth_ok_on_ack;
int dpp_in_response_listen;
int dpp_gas_client;
@@ -1237,8 +1359,23 @@ struct wpa_supplicant {
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+ u8 dpp_last_ssid[SSID_MAX_LEN];
+ size_t dpp_last_ssid_len;
+ bool dpp_conf_backup_received;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
+ int dpp_pfs_fallback;
+ struct wpabuf *dpp_presence_announcement;
+ struct dpp_bootstrap_info *dpp_chirp_bi;
+ int dpp_chirp_freq;
+ int *dpp_chirp_freqs;
+ int dpp_chirp_iter;
+ int dpp_chirp_round;
+ int dpp_chirp_scan_done;
+ int dpp_chirp_listen;
+ struct wpa_ssid *dpp_reconfig_ssid;
+ int dpp_reconfig_ssid_id;
+ struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1254,6 +1391,17 @@ struct wpa_supplicant {
unsigned int ieee80211ac:1;
unsigned int enabled_4addr_mode:1;
unsigned int multi_bss_support:1;
+ unsigned int drv_authorized_port:1;
+ unsigned int multi_ap_ie:1;
+ unsigned int multi_ap_backhaul:1;
+ unsigned int multi_ap_fronthaul:1;
+ struct robust_av_data robust_av;
+ bool mscs_setup_done;
+
+#ifdef CONFIG_PASN
+ struct wpas_pasn pasn;
+ struct wpa_radio_work *pasn_auth_work;
+#endif /* CONFIG_PASN */
};
@@ -1264,6 +1412,9 @@ void wpa_supplicant_apply_ht_overrides(
void wpa_supplicant_apply_vht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -1274,9 +1425,12 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
const char * wpa_supplicant_state_txt(enum wpa_states state);
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
u8 *wpa_ie, size_t *wpa_ie_len);
+int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s);
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss,
struct wpa_ssid *ssid);
@@ -1295,9 +1449,11 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
u16 reason_code);
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s);
struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1345,6 +1501,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
void fils_connection_failure(struct wpa_supplicant *wpa_s);
+void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
@@ -1360,6 +1517,16 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
void add_freq(int *freqs, int *num_freqs, int freq);
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type);
+
+int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
+ int mantissa, u8 min_twt, int setup_cmd, u64 twt,
+ bool requestor, bool trigger, bool implicit,
+ bool flow_type, u8 flow_id, bool protection,
+ u8 twt_channel, u8 control);
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
+
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
@@ -1382,6 +1549,8 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
struct scan_info *info);
void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s);
/* MBO functions */
@@ -1389,6 +1558,8 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
int add_oce_capa);
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid);
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
enum mbo_attr_id attr);
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
@@ -1412,11 +1583,12 @@ enum chan_allowed {
NOT_ALLOWED, NO_IR, ALLOWED
};
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw);
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw);
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len);
+ struct wpa_bss *bss, u8 *pos, size_t len);
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s);
int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
@@ -1457,6 +1629,9 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
struct channel_list_changed *info);
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *seleceted);
/* eap_register.c */
int eap_register_methods(void);
@@ -1525,7 +1700,10 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode);
+ u16 num_modes, enum hostapd_hw_mode mode,
+ bool is_6ghz);
+struct hostapd_hw_modes * get_mode_with_freq(struct hostapd_hw_modes *modes,
+ u16 num_modes, int freq);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
unsigned int sec, int rssi_threshold);
@@ -1546,4 +1724,27 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s);
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf);
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len);
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len);
+
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
+ const u8 *bssid, int akmp, int cipher,
+ u16 group, int network_id,
+ const u8 *comeback, size_t comeback_len);
+void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
+int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t data_len, u8 acked);
+int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len);
+
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/contrib/wpa/wpa_supplicant/wpas_glue.c b/contrib/wpa/wpa_supplicant/wpas_glue.c
index 62af7f6b1013..96818697882f 100644
--- a/contrib/wpa/wpa_supplicant/wpas_glue.c
+++ b/contrib/wpa/wpa_supplicant/wpas_glue.c
@@ -16,6 +16,7 @@
#include "config.h"
#include "l2_packet/l2_packet.h"
#include "common/wpa_common.h"
+#include "common/ptksa_cache.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "rsn_supp/pmksa_cache.h"
@@ -94,8 +95,8 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
* @len: Frame payload length
* Returns: >=0 on success, <0 on failure
*/
-static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
- u16 proto, const u8 *buf, size_t len)
+int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len)
{
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
@@ -112,6 +113,14 @@ static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+ int encrypt = wpa_s->wpa &&
+ wpa_sm_has_ptk_installed(wpa_s->wpa);
+
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
+ }
+
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
}
@@ -219,6 +228,7 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
}
+#ifdef CONFIG_WEP
/**
* wpa_eapol_set_wep_key - set WEP key for the driver
* @ctx: Pointer to wpa_supplicant data (wpa_s)
@@ -242,8 +252,11 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
}
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
unicast ? wpa_s->bssid : NULL,
- keyidx, unicast, NULL, 0, key, keylen);
+ keyidx, unicast, NULL, 0, key, keylen,
+ unicast ? KEY_FLAG_PAIRWISE_RX_TX :
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
}
+#endif /* CONFIG_WEP */
static void wpa_supplicant_aborted_cached(void *ctx)
@@ -340,8 +353,8 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
"handshake", pmk, pmk_len);
- if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
- pmk_len)) {
+ if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk,
+ pmk_len, KEY_FLAG_PMK)) {
wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
}
@@ -386,6 +399,13 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
curr = bss;
break;
}
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ (bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ curr = bss;
+ break;
+ }
+#endif /* CONFIG_OWE */
}
if (curr) {
@@ -396,6 +416,10 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+ if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}
@@ -472,6 +496,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static void * wpa_supplicant_get_network_ctx(void *wpa_s)
{
return wpa_supplicant_get_ssid(wpa_s);
@@ -488,7 +518,8 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct wpa_supplicant *wpa_s = _wpa_s;
if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -503,7 +534,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
}
#endif /* CONFIG_TESTING_GET_GTK */
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (addr && !is_broadcast_ether_addr(addr) &&
+ !(key_flag & KEY_FLAG_MODIFY)) {
wpa_s->last_tk_alg = alg;
os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
wpa_s->last_tk_key_idx = key_idx;
@@ -513,7 +545,7 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
}
#endif /* CONFIG_TESTING_OPTIONS */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -543,7 +575,9 @@ static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -551,9 +585,22 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
os_memset(&params, 0, sizeof(params));
ssid = wpas_get_network_ctx(wpa_s, network_ctx);
- if (ssid)
+ if (ssid) {
wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
MAC2STR(bssid), ssid->id);
+ if ((akmp == WPA_KEY_MGMT_FT_IEEE8021X ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ !ssid->ft_eap_pmksa_caching) {
+ /* Since we will not be using PMKSA caching for FT-EAP
+ * within wpa_supplicant to avoid known interop issues
+ * with APs, do not add this PMKID to the driver either
+ * so that we won't be hitting those interop issues
+ * with driver-based RSNE generation. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Do not add PMKID entry to the driver since FT-EAP PMKSA caching is not enabled in configuration");
+ return 0;
+ }
+ }
if (ssid && fils_cache_id) {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
@@ -565,6 +612,8 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
params.pmkid = pmkid;
params.pmk = pmk;
params.pmk_len = pmk_len;
+ params.pmk_lifetime = pmk_lifetime;
+ params.pmk_reauth_threshold = pmk_reauth_threshold;
return wpa_drv_add_pmkid(wpa_s, &params);
}
@@ -729,6 +778,8 @@ static int wpa_supplicant_tdls_peer_addset(
const u8 *supp_rates, size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len,
const u8 *supp_channels, size_t supp_channels_len,
const u8 *supp_oper_classes, size_t supp_oper_classes_len)
@@ -752,6 +803,8 @@ static int wpa_supplicant_tdls_peer_addset(
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
+ params.he_capab = he_capab;
+ params.he_capab_len = he_capab_len;
params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;
@@ -1043,6 +1096,21 @@ static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
}
+static int wpa_supplicant_eap_auth_start_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey &&
+ !wpa_sm_ext_key_id_active(wpa_s->wpa)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_supplicant_reconnect(wpa_s);
+ return -1;
+ }
+ return 0;
+}
+
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1098,7 +1166,9 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->preauth = 0;
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
+#ifdef CONFIG_WEP
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
@@ -1121,6 +1191,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
+ ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
@@ -1156,8 +1227,8 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
if (wpa_s->conf->key_mgmt_offload &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
- return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
- NULL, 0, pmk, pmk_len);
+ return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0,
+ NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
else
return 0;
}
@@ -1189,6 +1260,101 @@ static int wpa_supplicant_channel_info(void *_wpa_s,
return wpa_drv_channel_info(wpa_s, ci);
}
+
+static void disable_wpa_wpa2(struct wpa_ssid *ssid)
+{
+ ssid->proto &= ~WPA_PROTO_WPA;
+ ssid->proto |= WPA_PROTO_RSN;
+ ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+ ssid->group_cipher &= ~WPA_CIPHER_TKIP;
+ if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)))
+ ssid->group_cipher |= WPA_CIPHER_CCMP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+}
+
+
+static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+ int changed = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap);
+
+ ssid = wpa_s->current_ssid;
+ if (!ssid)
+ return;
+
+#ifdef CONFIG_SAE
+ if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "WPA3-Personal transition mode disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_SAE_PK) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+#ifdef CONFIG_SME
+ wpa_s->sme.sae.state == SAE_ACCEPTED &&
+ wpa_s->sme.sae.pk &&
+#endif /* CONFIG_SME */
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->sae_pk != SAE_PK_MODE_ONLY ||
+ ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: SAE authentication without PK disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ ssid->sae_pk = SAE_PK_MODE_ONLY;
+ changed = 1;
+ }
+#endif /* CONFIG_SAE */
+
+ if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
+ ssid->owe_only = 1;
+ changed = 1;
+ }
+
+ if (!changed)
+ return;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpa_supplicant_store_ptk(void *ctx, u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ ptksa_cache_add(wpa_s->ptksa, addr, cipher, life_time, ptk);
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1196,9 +1362,20 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
struct wpa_sm_ctx *ctx;
+
+ wpa_s->ptksa = ptksa_cache_init();
+ if (!wpa_s->ptksa) {
+ wpa_printf(MSG_ERROR, "Failed to allocate PTKSA");
+ return -1;
+ }
+
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
+
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
+
return -1;
}
@@ -1207,6 +1384,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->reconnect = _wpa_supplicant_reconnect;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -1240,12 +1418,16 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
ctx->channel_info = wpa_supplicant_channel_info;
+ ctx->transition_disable = wpa_supplicant_transition_disable;
+ ctx->store_ptk = wpa_supplicant_store_ptk;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
- wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
- "machine");
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize WPA state machine");
os_free(ctx);
+ ptksa_cache_deinit(wpa_s->ptksa);
+ wpa_s->ptksa = NULL;
return -1;
}
#endif /* CONFIG_NO_WPA */
@@ -1271,6 +1453,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+ conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
+ conf.owe_ptk_workaround = ssid->owe_ptk_workaround;
#ifdef CONFIG_P2P
if (ssid->p2p_group && wpa_s->current_bss &&
!wpa_s->p2p_disable_ip_addr_req) {
@@ -1293,6 +1477,16 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.fils_cache_id =
wpa_bss_get_fils_cache_id(wpa_s->current_bss);
#endif /* CONFIG_FILS */
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION) ||
+ (wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT))
+ conf.beacon_prot = ssid->beacon_prot;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ conf.force_kdk_derivation = wpa_s->conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/contrib/wpa/wpa_supplicant/wpas_glue.h b/contrib/wpa/wpa_supplicant/wpas_glue.h
index 5585e5615a65..338af4e650a7 100644
--- a/contrib/wpa/wpa_supplicant/wpas_glue.h
+++ b/contrib/wpa/wpa_supplicant/wpas_glue.h
@@ -15,6 +15,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
+int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len);
const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
const char *default_txt,
diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.c b/contrib/wpa/wpa_supplicant/wpas_kay.c
index 41477d514d3f..defd0f2f7e81 100644
--- a/contrib/wpa/wpa_supplicant/wpas_kay.c
+++ b/contrib/wpa/wpa_supplicant/wpas_kay.c
@@ -44,19 +44,19 @@ static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap)
}
-static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
+static int wpas_enable_protect_frames(void *wpa_s, bool enabled)
{
return wpa_drv_enable_protect_frames(wpa_s, enabled);
}
-static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+static int wpas_enable_encrypt(void *wpa_s, bool enabled)
{
return wpa_drv_enable_encrypt(wpa_s, enabled);
}
-static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
+static int wpas_set_replay_protect(void *wpa_s, bool enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
}
@@ -68,7 +68,7 @@ static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
}
-static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
+static int wpas_enable_controlled_port(void *wpa_s, bool enabled)
{
return wpa_drv_enable_controlled_port(wpa_s, enabled);
}
@@ -376,7 +376,7 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
- EAP_EXCHANGE, FALSE);
+ EAP_EXCHANGE, false);
fail:
if (msk) {
@@ -424,7 +424,7 @@ void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
ckn->len = ssid->mka_ckn_len;
os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
- res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, false);
if (res)
goto free_cak;
diff --git a/contrib/wpa/wpa_supplicant/wpas_module_tests.c b/contrib/wpa/wpa_supplicant/wpas_module_tests.c
index 4e37591be36c..ce5398cb851a 100644
--- a/contrib/wpa/wpa_supplicant/wpas_module_tests.c
+++ b/contrib/wpa/wpa_supplicant/wpas_module_tests.c
@@ -11,60 +11,77 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "wpa_supplicant_i.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
-static int wpas_blacklist_module_tests(void)
+static int wpas_bssid_ignore_module_tests(void)
{
struct wpa_supplicant wpa_s;
int ret = -1;
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_blacklist_clear(&wpa_s);
+ wpa_bssid_ignore_clear(&wpa_s);
- if (wpa_blacklist_get(NULL, NULL) != NULL ||
- wpa_blacklist_get(NULL, (u8 *) "123456") != NULL ||
- wpa_blacklist_get(&wpa_s, NULL) != NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "123456") != NULL)
+ if (wpa_bssid_ignore_get(NULL, NULL) != NULL ||
+ wpa_bssid_ignore_get(NULL, (u8 *) "123456") != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, NULL) != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "123456") != NULL)
goto fail;
- if (wpa_blacklist_add(NULL, NULL) == 0 ||
- wpa_blacklist_add(NULL, (u8 *) "123456") == 0 ||
- wpa_blacklist_add(&wpa_s, NULL) == 0)
+ if (wpa_bssid_ignore_add(NULL, NULL) == 0 ||
+ wpa_bssid_ignore_add(NULL, (u8 *) "123456") == 0 ||
+ wpa_bssid_ignore_add(&wpa_s, NULL) == 0)
goto fail;
- if (wpa_blacklist_del(NULL, NULL) == 0 ||
- wpa_blacklist_del(NULL, (u8 *) "123456") == 0 ||
- wpa_blacklist_del(&wpa_s, NULL) == 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "123456") == 0)
+ if (wpa_bssid_ignore_del(NULL, NULL) == 0 ||
+ wpa_bssid_ignore_del(NULL, (u8 *) "123456") == 0 ||
+ wpa_bssid_ignore_del(&wpa_s, NULL) == 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "123456") == 0)
goto fail;
- if (wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "444444") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "333333") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "xxxxxx") == 0 ||
- wpa_blacklist_get(&wpa_s, (u8 *) "xxxxxx") != NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "111111") == NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "222222") == NULL ||
- wpa_blacklist_get(&wpa_s, (u8 *) "444444") == NULL ||
- wpa_blacklist_del(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_del(&wpa_s, (u8 *) "444444") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
- wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0)
+ if (wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "xxxxxx") == 0 ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "xxxxxx") != NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "111111") == NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "222222") == NULL ||
+ wpa_bssid_ignore_get(&wpa_s, (u8 *) "444444") == NULL ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0)
+ goto fail;
+
+ wpa_bssid_ignore_clear(&wpa_s);
+
+ if (wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "444444") < 0 ||
+ !wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111") ||
+ wpa_bssid_ignore_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111") ||
+ wpa_bssid_ignore_add(&wpa_s, (u8 *) "111111") < 0)
+ goto fail;
+
+ wpa_bssid_ignore_update(&wpa_s);
+
+ if (!wpa_bssid_ignore_is_listed(&wpa_s, (u8 *) "111111"))
goto fail;
ret = 0;
fail:
- wpa_blacklist_clear(&wpa_s);
+ wpa_bssid_ignore_clear(&wpa_s);
if (ret)
- wpa_printf(MSG_ERROR, "blacklist module test failure");
+ wpa_printf(MSG_ERROR, "bssid_ignore module test failure");
return ret;
}
@@ -76,7 +93,7 @@ int wpas_module_tests(void)
wpa_printf(MSG_INFO, "wpa_supplicant module tests");
- if (wpas_blacklist_module_tests() < 0)
+ if (wpas_bssid_ignore_module_tests() < 0)
ret = -1;
#ifdef CONFIG_WPS
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.c b/contrib/wpa/wpa_supplicant/wps_supplicant.c
index 057927410256..5633f3d1ecaf 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.c
@@ -26,7 +26,7 @@
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "notify.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "bss.h"
#include "scan.h"
#include "ap.h"
@@ -94,14 +94,14 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
" did not succeed - continue trying to find "
"suitable AP", MAC2STR(bssid));
- wpa_blacklist_add(wpa_s, bssid);
+ wpa_bssid_ignore_add(wpa_s, bssid);
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s,
- wpa_s->blacklist_cleared ? 5 : 0, 0);
- wpa_s->blacklist_cleared = 0;
+ wpa_s->bssid_ignore_cleared ? 5 : 0, 0);
+ wpa_s->bssid_ignore_cleared = false;
return 1;
}
@@ -188,6 +188,7 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
const u8 *ie;
struct wpa_ie_data adv;
int wpa2 = 0, ccmp = 0;
+ enum wpa_driver_if_type iftype;
/*
* Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
@@ -239,9 +240,12 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
return;
}
+ iftype = ssid->p2p_group ? WPA_IF_P2P_CLIENT : WPA_IF_STATION;
+
if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
(ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
- (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ (capa.key_mgmt_iftype[iftype] &
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
"based on scan results");
if (wpa_s->conf->ap_scan == 1)
@@ -368,6 +372,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
#ifdef CONFIG_WPS_REG_DISABLE_OPEN
int registrar = 0;
#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
+ bool add_sae;
if ((wpa_s->conf->wps_cred_processing == 1 ||
wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
@@ -484,7 +489,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_ENCR_NONE:
break;
case WPS_ENCR_TKIP:
- ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+ ssid->pairwise_cipher = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
@@ -525,17 +530,20 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_AUTH_WPAPSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
- ssid->proto = WPA_PROTO_WPA;
+ ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
- if (wpa_s->conf->wps_cred_add_sae &&
- cred->key_len != 2 * PMK_LEN) {
+ add_sae = wpa_s->conf->wps_cred_add_sae;
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group && is_p2p_6ghz_capable(wpa_s->global->p2p))
+ add_sae = true;
+#endif /* CONFIG_P2P */
+ if (add_sae && cred->key_len != 2 * PMK_LEN) {
+ ssid->auth_alg = 0;
ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
-#endif /* CONFIG_IEEE80211W */
}
ssid->proto = WPA_PROTO_RSN;
break;
@@ -717,7 +725,7 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
wpas_notify_wps_event_success(wpa_s);
if (wpa_s->current_ssid)
wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
/*
* Enable the networks disabled during wpas_wps_reassoc after 10
@@ -1136,7 +1144,7 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
wpa_s->scan_runs = 0;
wpa_s->normal_scans = 0;
wpa_s->wps_success = 0;
- wpa_s->blacklist_cleared = 0;
+ wpa_s->bssid_ignore_cleared = false;
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1180,6 +1188,11 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1263,6 +1276,11 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1286,6 +1304,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
return -1;
}
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
+
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -1351,6 +1373,7 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
wpas_clear_wps(wpa_s);
}
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
wpa_s->after_wps = 0;
return 0;
@@ -1604,8 +1627,13 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
wpas_wps_set_uuid(wpa_s, wps);
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
os_memset(&rcfg, 0, sizeof(rcfg));
rcfg.new_psk_cb = wpas_wps_new_psk_cb;
@@ -1816,6 +1844,10 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
"present in scan results; selected BSSID " MACSTR,
MAC2STR(selected->bssid));
+ if (!is_zero_ether_addr(ssid->bssid))
+ wpa_printf(MSG_DEBUG,
+ "WPS: Network profile limited to accept only a single BSSID " MACSTR,
+ MAC2STR(ssid->bssid));
/* Make sure that only one AP is in active PBC mode */
wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
@@ -1836,6 +1868,14 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
continue;
+ if (!is_zero_ether_addr(ssid->bssid) &&
+ os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
+ " in active PBC mode due to local BSSID limitation",
+ MAC2STR(ap->bssid));
+ continue;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
@@ -2235,6 +2275,16 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
}
+void wpas_wps_update_mac_addr(struct wpa_supplicant *wpa_s)
+{
+ struct wps_context *wps;
+
+ wps = wpa_s->wps;
+ if (wps)
+ os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
+}
+
+
#ifdef CONFIG_WPS_NFC
#ifdef CONFIG_WPS_ER
@@ -2681,7 +2731,7 @@ static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_50GHZ))
freq = 5000 + 5 * chan;
- else if (chan >= 1 && chan <= 4 &&
+ else if (chan >= 1 && chan <= 6 &&
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_60GHZ))
freq = 56160 + 2160 * chan;
@@ -2838,10 +2888,11 @@ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
for (i = 0; i < wpa_s->num_wps_ap; i++) {
struct wps_ap_info *ap = &wpa_s->wps_ap[i];
- struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+ struct wpa_bssid_ignore *e = wpa_bssid_ignore_get(wpa_s,
+ ap->bssid);
wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
- "tries=%d last_attempt=%d sec ago blacklist=%d",
+ "tries=%d last_attempt=%d sec ago bssid_ignore=%d",
(int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
ap->last_attempt.sec > 0 ?
(int) now.sec - (int) ap->last_attempt.sec : -1,
@@ -2903,7 +2954,7 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
MAC2STR(res->bssid), ap->type, type);
ap->type = type;
if (type != WPS_AP_NOT_SEL_REG)
- wpa_blacklist_del(wpa_s, ap->bssid);
+ wpa_bssid_ignore_del(wpa_s, ap->bssid);
}
ap->pbc_active = pbc_active;
if (uuid)
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.h b/contrib/wpa/wpa_supplicant/wps_supplicant.h
index 0fbc85174f94..c55936ceeaaf 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.h
@@ -62,6 +62,7 @@ struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef, const char *uuid);
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+void wpas_wps_update_mac_addr(struct wpa_supplicant *wpa_s);
struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef, const char *id_str);
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
@@ -154,6 +155,10 @@ wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
return 0;
}
+static inline void wpas_wps_update_mac_addr(struct wpa_supplicant *wpa_s)
+{
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */
diff --git a/usr.sbin/wpa/Makefile.crypto b/usr.sbin/wpa/Makefile.crypto
index a65ee29e0ebe..2046c32d76ac 100644
--- a/usr.sbin/wpa/Makefile.crypto
+++ b/usr.sbin/wpa/Makefile.crypto
@@ -3,6 +3,7 @@
.if ${MK_OPENSSL} != "no"
LIBADD+= ssl crypto
CFLAGS+= -DCONFIG_SHA256
+CFLAGS+= -DCONFIG_ECC
.else
CFLAGS+=-DCONFIG_CRYPTO_INTERNAL
CONFIG_INTERNAL_AES=y
diff --git a/usr.sbin/wpa/Makefile.inc b/usr.sbin/wpa/Makefile.inc
index ef94c7b312a9..49c7344e8957 100644
--- a/usr.sbin/wpa/Makefile.inc
+++ b/usr.sbin/wpa/Makefile.inc
@@ -40,8 +40,6 @@ CFLAGS+=-DCONFIG_IEEE80211AC
CFLAGS+=-DCONFIG_IEEE80211N
CFLAGS+=-DCONFIG_IEEE80211R
CFLAGS+=-DCONFIG_IEEE80211W
-CFLAGS+=-DCONFIG_IEEE80211AX
-CFLAGS+=-DNEED_AP_MLME
CFLAGS+=-DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"
CFLAGS+=-DCONFIG_DEBUG_SYSLOG
CFLAGS+=-DCONFIG_WPS
@@ -54,9 +52,12 @@ CFLAGS+=-DCONFIG_GAS
CFLAGS+=-DCONFIG_PEERKEY
CFLAGS+=-DCONFIG_PRIVSEP
CFLAGS+=-DCONFIG_SMARTCARD
+CFLAGS+=-DCONFIG_TDLS
CFLAGS+=-DCONFIG_TERMINATE_ONLASTIF
CFLAGS+=-DCONFIG_TLS=openssl
CFLAGS+=-DCONFIG_MATCH_IFACE
+CFLAGS+=-DCONFIG_PASN
+CFLAGS+=-DCONFIG_PTKSA_CACHE
CFLAGS+=-DEAP_SERVER
CFLAGS+=-DEAP_SERVER_GTC
CFLAGS+=-DEAP_SERVER_IDENTITY
diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile
index 1ae4481a863e..ce3b7d82fd69 100644
--- a/usr.sbin/wpa/hostapd/Makefile
+++ b/usr.sbin/wpa/hostapd/Makefile
@@ -26,8 +26,6 @@ FILES= hostapd.conf hostapd.eap_user hostapd.wpa_psk
CFLAGS+=-I${.CURDIR:H}/wpa_supplicant \
-I${WPA_DISTDIR}/src/eap_peer \
- -DCONFIG_MBO \
- -DCONFIG_RSN_PREAUTH \
-DHOSTAPD
.if ${MK_INET6} != "no"
CFLAGS+= -DCONFIG_IPV6
diff --git a/usr.sbin/wpa/src/ap/Makefile b/usr.sbin/wpa/src/ap/Makefile
index 77caf1ed8efe..b6d53b0d5dbb 100644
--- a/usr.sbin/wpa/src/ap/Makefile
+++ b/usr.sbin/wpa/src/ap/Makefile
@@ -12,7 +12,6 @@ INTERNALLIB=
SRCS= accounting.c \
ap_config.c \
ap_drv_ops.c \
- ap_list.c \
ap_mlme.c \
authsrv.c \
beacon.c \
@@ -24,15 +23,11 @@ SRCS= accounting.c \
gas_serv.c \
hostapd.c \
hs20.c \
- hw_features.c \
- ieee802_11.c \
ieee802_11_auth.c \
- ieee802_11_he.c \
ieee802_11_ht.c \
ieee802_11_shared.c \
ieee802_11_vht.c \
ieee802_1x.c \
- mbo_ap.c \
neighbor_db.c \
pmksa_cache_auth.c \
preauth_auth.c \
@@ -49,9 +44,7 @@ SRCS= accounting.c \
wpa_auth_ie.c \
wps_hostapd.c
-CFLAGS+=-DCONFIG_MBO \
- -DCONFIG_RSN_PREAUTH \
- -DHOSTAPD
+CFLAGS+=-DHOSTAPD
# We are only interested in includes at this point. Not libraries.
LIBADD=
diff --git a/usr.sbin/wpa/src/common/Makefile b/usr.sbin/wpa/src/common/Makefile
index b415b926c207..ed27c3eb6bf4 100644
--- a/usr.sbin/wpa/src/common/Makefile
+++ b/usr.sbin/wpa/src/common/Makefile
@@ -11,9 +11,12 @@ INTERNALLIB=
SRCS= cli.c \
ctrl_iface_common.c \
+ dragonfly.c \
+ dpp_tcp.c \
gas.c \
hw_features_common.c \
ieee802_11_common.c \
+ ptksa_cache.c \
wpa_common.c \
wpa_ctrl.c
diff --git a/usr.sbin/wpa/src/crypto/Makefile b/usr.sbin/wpa/src/crypto/Makefile
index b25489072425..c95834279c21 100644
--- a/usr.sbin/wpa/src/crypto/Makefile
+++ b/usr.sbin/wpa/src/crypto/Makefile
@@ -15,6 +15,8 @@ SRCS= crypto_openssl.c \
sha1-prf.c \
sha256-prf.c \
sha256-tlsprf.c \
+ sha384-prf.c \
+ sha384-tlsprf.c \
sha512.c
.else
SRCS= crypto_internal.c \
@@ -109,7 +111,8 @@ SRCS+= sha256-internal.c \
SRCS+= sha384.c
.if defined(CONFIG_INTERNAL_SHA384)
SRCS+= sha384-internal.c \
- sha384-prf.c
+ sha384-prf.c \
+ sha384-tlsprf.c
.endif
.endif
diff --git a/usr.sbin/wpa/src/rsn_supp/Makefile b/usr.sbin/wpa/src/rsn_supp/Makefile
index 4d952c2204c4..3ffa1e524890 100644
--- a/usr.sbin/wpa/src/rsn_supp/Makefile
+++ b/usr.sbin/wpa/src/rsn_supp/Makefile
@@ -16,10 +16,6 @@ SRCS= pmksa_cache.c \
wpa.c \
wpa_ie.c
-CFLAGS+=-DCONFIG_TDLS \
- -DCONFIG_WNM \
- -DIEEE8021X_EAPOL
-
# We are only interested in includes at this point. Not libraries.
LIBADD=
diff --git a/usr.sbin/wpa/src/utils/Makefile b/usr.sbin/wpa/src/utils/Makefile
index 22ec732a2b3b..061ddeaad6f8 100644
--- a/usr.sbin/wpa/src/utils/Makefile
+++ b/usr.sbin/wpa/src/utils/Makefile
@@ -11,7 +11,9 @@ INTERNALLIB=
SRCS= base64.c \
bitfield.c \
+ crc32.c \
common.c \
+ config.c \
edit.c \
eloop.c \
ip_addr.c \
diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile
index 27bf83d29f7e..b437d2991360 100644
--- a/usr.sbin/wpa/wpa_supplicant/Makefile
+++ b/usr.sbin/wpa/wpa_supplicant/Makefile
@@ -12,8 +12,8 @@
PACKAGE= wpa
PROG= wpa_supplicant
-SRCS= blacklist.c \
- bss.c \
+SRCS= bss.c \
+ bssid_ignore.c \
config.c \
config_file.c \
ctrl_iface.c \
@@ -26,8 +26,11 @@ SRCS= blacklist.c \
notify.c \
op_classes.c \
offchannel.c \
+ pasn_supplicant.c \
+ robust_av.c \
rrm.c \
scan.c \
+ twt.c \
wmm_ac.c \
wpa_supplicant.c \
wpas_glue.c